/desktop-storage-electron
Persistent storage, SQLite databases, and credential management in Electron apps
$ npx -y skills add agents-inc/skills --skill desktop-storage-electron --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/desktop-storage-electron
Context preview
The summary Claude sees to decide when to auto-load this skill.
Persistent storage, SQLite databases, and credential management in Electron apps
SKILL.md
desktop-storage-electron.SKILL.mdname: desktop-storage-electron
description: Persistent storage, SQLite databases, and credential management in Electron apps
Electron Storage & Credentials
> **Quick Guide:** Use `electron-store` for typed JSON preferences (small key-value config with schema validation, migrations, and file watching). Use `better-sqlite3` for structured/relational data or anything beyond simple key-value (synchronous, WAL mode, transactions). Use `safeStorage` for encrypting secrets like tokens and API keys via the OS keychain -- it replaces the deprecated `keytar`. All persistent data belongs under `app.getPath("userData")`. Never store secrets in plain JSON files.
---
<critical_requirements>
CRITICAL: Before Using This Skill
> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)
**(You MUST use `safeStorage.encryptString()` / `safeStorage.decryptString()` for secrets -- never store tokens, API keys, or passwords in plain text or in electron-store without OS-level encryption)**
**(You MUST store all persistent data under `app.getPath("userData")` -- never write to the app installation directory, which is replaced on updates)**
**(You MUST enable WAL mode (`PRAGMA journal_mode = WAL`) when using better-sqlite3 -- it prevents readers from blocking writers and avoids SQLITE_BUSY errors in multi-window apps)**
**(You MUST call `safeStorage.isEncryptionAvailable()` before encrypting -- it returns false before the app `ready` event and on some Linux configurations)**
**(You MUST rebuild better-sqlite3 for Electron's Node.js version using `@electron/rebuild` -- mismatched native bindings crash the app)**
</critical_requirements>
---
**Auto-detection:** electron-store, better-sqlite3, safeStorage, app.getPath, userData, encryptString, decryptString, isEncryptionAvailable, lowdb, JSONFilePreset, persistent storage, credential storage, keytar replacement, electron config, electron preferences, electron database
**When to use:**
- Persisting user preferences and app configuration
- Storing structured or relational data locally
- Encrypting tokens, API keys, or other secrets
- Choosing between storage solutions for an Electron app
- Migrating stored data between app versions
- Working with `app.getPath()` standard directories
**When NOT to use:**
- Choosing a UI framework or styling for the renderer (separate skill)
- IPC communication patterns between main and renderer (separate concern)
- Packaging and distribution concerns (separate concern)
- Server-side or cloud storage
**Key patterns covered:**
- electron-store: typed config, schema validation, migrations, encryption, watching
- better-sqlite3: WAL mode, prepared statements, transactions, native module rebuild
- safeStorage: OS keychain encryption for secrets, replacing keytar
- lowdb: lightweight JSON database for medium-complexity data
- Storage path conventions using `app.getPath()`
- Credential storage best practices
---
<philosophy>
Philosophy
Electron apps have access to the full filesystem but should store data in OS-designated locations. The right storage solution depends on data shape and sensitivity:
**Preferences and small config** (theme, window bounds, feature flags): `electron-store` writes a single JSON file atomically. It is read and written in full on every change, so it is only appropriate for small data (under ~1MB).
**Structured or queryable data** (chat history, project metadata, analytics): `better-sqlite3` provides a synchronous SQLite database with ACID transactions. It handles concurrent reads via WAL mode and scales to gigabytes.
**Secrets** (OAuth tokens, API keys, passwords): `safeStorage` uses the OS keychain (macOS Keychain, Windows DPAPI, Linux secret service) to encrypt strings. The encrypted buffer can be stored in electron-store or a file -- only your app can decrypt it on the same machine and user account.
**Medium-complexity JSON data** (todo lists, small document stores): `lowdb` provides a file-backed JavaScript object with native array methods. Simpler than SQLite for JSON-shaped data that does not need relational queries.
**Key principle:** Storage runs in the **main process**. Renderers request data via IPC. Never give renderers direct filesystem or database access.
</philosophy>
---
<patterns>
Core Patterns
Pattern 1: electron-store -- Typed Preferences
Use for small key-value configuration that persists across sessions. Supports schema validation, defaults, and migrations.
import Store from "electron-store";
interface AppSettings {
theme: "light" | "dark" | "system";
windowBounds: { width: number; height: number; x?: number; y?: number };
recentFiles: string[];
fontSize: number;
}
const DEFAULT_WIDTH = 1200;
const DEFAULT_HEIGHT = 800;
const MIN_FONT_SIZE = 8;
const MAX_FONT_SIZE = 72;
const DEFAULT_FONT_SIZE = 14;
const store = new Store<AppSettings>({
defaults: {
theme: "system",
windowBounds: { width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT },
recentFiles: [],
fontSize: DEFAULT_FONT_SIZE,
},
schema: {
fontSize: {
type: "number",
minimum: MIN_FONT_SIZE,
maximum: MAX_FONT_SIZE,
},
},
});**Why good:** Type-safe generic parameter ensures `.get()` and `.set()` are checked at compile time, named constants for all limits, schema rejects invalid values at write time
See [examples/core.md](examples/core.md) for migrations, file watching, dot-notation access, and renderer integration via IPC.
---
Pattern 2: better-sqlite3 -- Local Database
Use for structured data that benefits from queries, indexes, or transactions. Always enable WAL mode.
import Database from "better-sqlite3";
import { app } from "electron";
import path from "node:path";
const DB_FILE = "app-data.db";
const db = new Database(path.join(app.getPath("userData"), DB_FILE));
// Performance pragmas -- set once at connectRead more
name: desktop-storage-electron description: Persistent storage, SQLite databases, and credential management in Electron apps
Electron Storage & Credentials
> **Quick Guide:** Use `electron-store` for typed JSON preferences (small key-value config with schema validation, migrations, and file watching). Use `better-sqlite3` for structured/relational data or anything beyond simple key-value (synchronous, WAL mode, transactions). Use `safeStorage` for encrypting secrets like tokens and API keys via the OS keychain -- it replaces the deprecated `keytar`. All persistent data belongs under `app.getPath("userData")`. Never store secrets in plain JSON files.
---
<critical_requirements>
CRITICAL: Before Using This Skill
> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)
**(You MUST use `safeStorage.encryptString()` / `safeStorage.decryptString()` for secrets -- never store tokens, API keys, or passwords in plain text or in electron-store without OS-level encryption)**
**(You MUST store all persistent data under `app.getPath("userData")` -- never write to the app installation directory, which is replaced on updates)**
**(You MUST enable WAL mode (`PRAGMA journal_mode = WAL`) when using better-sqlite3 -- it prevents readers from blocking writers and avoids SQLITE_BUSY errors in multi-window apps)**
**(You MUST call `safeStorage.isEncryptionAvailable()` before encrypting -- it returns false before the app `ready` event and on some Linux configurations)**
**(You MUST rebuild better-sqlite3 for Electron's Node.js version using `@electron/rebuild` -- mismatched native bindings crash the app)**
</critical_requirements>
---
**Auto-detection:** electron-store, better-sqlite3, safeStorage, app.getPath, userData, encryptString, decryptString, isEncryptionAvailable, lowdb, JSONFilePreset, persistent storage, credential storage, keytar replacement, electron config, electron preferences, electron database
**When to use:**
- Persisting user preferences and app configuration
- Storing structured or relational data locally
- Encrypting tokens, API keys, or other secrets
- Choosing between storage solutions for an Electron app
- Migrating stored data between app versions
- Working with `app.getPath()` standard directories
**When NOT to use:**
- Choosing a UI framework or styling for the renderer (separate skill)
- IPC communication patterns between main and renderer (separate concern)
- Packaging and distribution concerns (separate concern)
- Server-side or cloud storage
**Key patterns covered:**
- electron-store: typed config, schema validation, migrations, encryption, watching
- better-sqlite3: WAL mode, prepared statements, transactions, native module rebuild
- safeStorage: OS keychain encryption for secrets, replacing keytar
- lowdb: lightweight JSON database for medium-complexity data
- Storage path conventions using `app.getPath()`
- Credential storage best practices
---
<philosophy>
Philosophy
Electron apps have access to the full filesystem but should store data in OS-designated locations. The right storage solution depends on data shape and sensitivity:
**Preferences and small config** (theme, window bounds, feature flags): `electron-store` writes a single JSON file atomically. It is read and written in full on every change, so it is only appropriate for small data (under ~1MB).
**Structured or queryable data** (chat history, project metadata, analytics): `better-sqlite3` provides a synchronous SQLite database with ACID transactions. It handles concurrent reads via WAL mode and scales to gigabytes.
**Secrets** (OAuth tokens, API keys, passwords): `safeStorage` uses the OS keychain (macOS Keychain, Windows DPAPI, Linux secret service) to encrypt strings. The encrypted buffer can be stored in electron-store or a file -- only your app can decrypt it on the same machine and user account.
**Medium-complexity JSON data** (todo lists, small document stores): `lowdb` provides a file-backed JavaScript object with native array methods. Simpler than SQLite for JSON-shaped data that does not need relational queries.
**Key principle:** Storage runs in the **main process**. Renderers request data via IPC. Never give renderers direct filesystem or database access.
</philosophy>
---
<patterns>
Core Patterns
Pattern 1: electron-store -- Typed Preferences
Use for small key-value configuration that persists across sessions. Supports schema validation, defaults, and migrations.
import Store from "electron-store";
interface AppSettings {
theme: "light" | "dark" | "system";
windowBounds: { width: number; height: number; x?: number; y?: number };
recentFiles: string[];
fontSize: number;
}
const DEFAULT_WIDTH = 1200;
const DEFAULT_HEIGHT = 800;
const MIN_FONT_SIZE = 8;
const MAX_FONT_SIZE = 72;
const DEFAULT_FONT_SIZE = 14;
const store = new Store<AppSettings>({
defaults: {
theme: "system",
windowBounds: { width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT },
recentFiles: [],
fontSize: DEFAULT_FONT_SIZE,
},
schema: {
fontSize: {
type: "number",
minimum: MIN_FONT_SIZE,
maximum: MAX_FONT_SIZE,
},
},
});**Why good:** Type-safe generic parameter ensures `.get()` and `.set()` are checked at compile time, named constants for all limits, schema rejects invalid values at write time
See [examples/core.md](examples/core.md) for migrations, file watching, dot-notation access, and renderer integration via IPC.
---
Pattern 2: better-sqlite3 -- Local Database
Use for structured data that benefits from queries, indexes, or transactions. Always enable WAL mode.
import Database from "better-sqlite3";
import { app } from "electron";
import path from "node:path";
const DB_FILE = "app-data.db";
const db = new Database(path.join(app.getPath("userData"), DB_FILE));
// Performance pragmas -- set once at connectShowing the first part of this file.
The official skills marketplace for Agents Inc. 150+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?
Repo: agents-inc/skills
Other skills on agents-inc-skills.
- /ai-infrastructure-huggingface-inference
Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints
Open skill - /ai-infrastructure-litellm
LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment
Open skill - /ai-infrastructure-modal
Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns
Open skill - /ai-infrastructure-ollama
Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint
Open skill - /ai-infrastructure-replicate
Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training
Open skill - /ai-infrastructure-together-ai
Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints
Open skill

