Simple data persistence for Electron apps using JSON storage with atomic writes
npx @tessl/cli install tessl/npm-electron-store@10.1.0Electron Store provides simple data persistence for Electron applications, handling user settings, app state, cache, and other data using JSON files stored in the app's userData directory. It extends the 'conf' package with Electron-specific functionality and supports both main and renderer processes.
npm install electron-storeimport Store from "electron-store";For TypeScript:
import Store, { Schema } from "electron-store";import Store from "electron-store";
const store = new Store();
// Set and get values
store.set('unicorn', '🦄');
console.log(store.get('unicorn'));
//=> '🦄'
// Use dot-notation for nested properties
store.set('foo.bar', true);
console.log(store.get('foo'));
//=> {bar: true}
// Delete values
store.delete('unicorn');
console.log(store.get('unicorn'));
//=> undefinedElectron Store is built around several key components:
Process Type Detection:
process.typePath Resolution Logic:
cwd option provided: resolves relative paths against Electron's userData directorycwd: defaults to app.getPath('userData')cwd are used as-isOption Transformation:
name option becomes configName internally (conf requirement)projectVersion defaults to app.getVersion() if not specifiedElectron-Store Specific Features:
static initRenderer(): Sets up IPC for renderer-only usageopenInEditor(): Opens config file in system editor (uses Electron's shell.openPath)Inherited from Conf Package:
set(), get(), has(), delete(), clear(), reset()onDidChange(), onDidAnyChange()size, store, pathCreates a new store instance with Electron-specific configuration.
/**
* Creates a new ElectronStore instance with optional configuration
* Inherits all conf package options except configName, projectName, projectVersion, projectSuffix
* @param options - Configuration options for the store
*/
constructor<T extends Record<string, any>>(options?: Options<T>): ElectronStore<T>;
/**
* Options interface extends conf's ConfigOptions with exclusions
* Excludes: configName, projectName, projectVersion, projectSuffix (handled internally)
*/
type Options<T extends Record<string, any>> = Except<ConfigOptions<T>, 'configName' | 'projectName' | 'projectVersion' | 'projectSuffix'> & {
/** Name of the storage file (without extension). Default: 'config' */
readonly name?: string;
};
/**
* Inherited ConfigOptions from conf package include:
* - defaults: Default values for store items
* - schema: JSON Schema for validation
* - rootSchema: Top-level schema properties
* - ajvOptions: JSON Schema validator options
* - migrations: Version-based migration handlers
* - cwd: Custom config directory (auto-resolved to userData by electron-store)
* - encryptionKey: Optional encryption key for obfuscation
* - fileExtension: Config file extension (default: 'json')
* - clearInvalidConfig: Clear config on syntax errors (default: false)
* - serialize: Custom serialization function
* - deserialize: Custom deserialization function
* - accessPropertiesByDotNotation: Enable dot notation (default: true)
* - watch: Watch config file for changes (default: false)
* - configFileMode: File permissions for config file
*/
interface MigrationContext {
fromVersion: string;
toVersion: string;
finalVersion: string;
versions: string[];
}Initializes IPC communication channels when using store only in renderer process.
/**
* Initializer to set up required IPC communication channels
* Call this from the main process when creating Store instances only in renderer process
*/
static initRenderer(): void;Note: All methods below are inherited from the conf package, with ElectronStore providing Electron-specific initialization and path handling.
Core methods for getting, setting, and managing stored data (inherited from conf).
/**
* Set a single item in the store
* @param key - Property key (supports dot-notation for nested properties)
* @param value - Value to store (must be JSON serializable)
*/
set(key: string, value: any): void;
/**
* Set multiple items at once
* @param object - Object with key-value pairs to store
*/
set(object: Partial<T>): void;
/**
* Get an item from the store
* @param key - Property key (supports dot-notation)
* @param defaultValue - Default value if key doesn't exist
* @returns The stored value or defaultValue
*/
get(key: string, defaultValue?: any): any;
/**
* Check if an item exists in the store
* @param key - Property key to check
* @returns true if key exists, false otherwise
*/
has(key: string): boolean;
/**
* Delete an item from the store
* @param key - Property key to delete
*/
delete(key: string): void;
/**
* Delete all items from the store
* Resets known items to their default values if defined by defaults or schema
*/
clear(): void;
/**
* Reset items to their default values
* @param keys - Keys to reset to default values
*/
reset(...keys: string[]): void;Methods for observing changes to stored data (inherited from conf).
/**
* Watch for changes on a specific key
* @param key - Key to watch for changes
* @param callback - Function called when key changes
* @returns Function to unsubscribe from changes
*/
onDidChange(key: string, callback: (newValue: any, oldValue: any) => void): () => void;
/**
* Watch for any changes to the store
* @param callback - Function called when any value changes
* @returns Function to unsubscribe from changes
*/
onDidAnyChange(callback: (newValue: T, oldValue: T) => void): () => void;Method for opening the storage file in an external editor.
/**
* Open the storage file in the user's default editor
* @returns Promise that resolves when editor opens or rejects on failure
*/
openInEditor(): Promise<void>;Properties providing access to store metadata and data (inherited from conf).
/**
* Get the number of items in the store
*/
readonly size: number;
/**
* Get or set all data as an object
* Setting this property replaces all store data
*/
store: T;
/**
* Get the path to the storage file
*/
readonly path: string;Re-exported type from the 'conf' package for JSON Schema validation.
/**
* JSON Schema type for validation configuration
* Re-exported from 'conf' package
*/
export { Schema } from 'conf';import Store from "electron-store";
const store = new Store();
// Store different data types
store.set('user.name', 'Alice');
store.set('user.preferences', { theme: 'dark', language: 'en' });
store.set('recentFiles', ['file1.txt', 'file2.txt']);
// Check and retrieve data
if (store.has('user.name')) {
console.log(`Hello, ${store.get('user.name')}!`);
}
// Get with default value
const theme = store.get('user.preferences.theme', 'light');import Store from "electron-store";
const schema = {
user: {
type: 'object',
properties: {
name: { type: 'string', minLength: 1 },
age: { type: 'number', minimum: 0 }
},
required: ['name']
},
settings: {
type: 'object',
properties: {
theme: { type: 'string', enum: ['light', 'dark'] }
},
default: { theme: 'light' }
}
};
const store = new Store({ schema });
// This will work
store.set('user', { name: 'Bob', age: 25 });
// This will throw an error due to schema validation
// store.set('user', { age: 25 }); // Missing required 'name'In the main process:
import Store from "electron-store";
// Option 1: Create store in main process (accessible anywhere)
const store = new Store();
// Option 2: Initialize for renderer-only usage
Store.initRenderer();In the renderer process:
import Store from "electron-store";
// If using option 1, create another instance
const store = new Store();
// If using option 2, this works without main process store
const store = new Store();
store.set('renderer-data', 'Hello from renderer!');import Store from "electron-store";
const store = new Store({ watch: true });
// Watch specific key changes
const unsubscribe = store.onDidChange('user.theme', (newValue, oldValue) => {
console.log(`Theme changed from ${oldValue} to ${newValue}`);
// Update UI theme
});
// Watch all changes
const unsubscribeAll = store.onDidAnyChange((newStore, oldStore) => {
console.log('Store updated:', newStore);
});
// Unsubscribe when no longer needed
unsubscribe();
unsubscribeAll();import Store from "electron-store";
const store = new Store({
migrations: {
'0.1.0': store => {
// Migration from version 0.1.0
store.set('newFeatureEnabled', true);
},
'1.0.0': store => {
// Migration from version 1.0.0
const oldData = store.get('deprecatedKey');
if (oldData) {
store.set('newKey', oldData);
store.delete('deprecatedKey');
}
}
},
beforeEachMigration: (store, context) => {
console.log(`Migrating from ${context.fromVersion} to ${context.toVersion}`);
}
});import Store from "electron-store";
import path from "node:path";
const store = new Store({
name: 'user-settings',
cwd: path.join(__dirname, 'custom-config'),
encryptionKey: 'my-secret-key', // For obfuscation only
fileExtension: 'conf'
});
// Storage file will be at: custom-config/user-settings.conf
console.log('Config stored at:', store.path);Renderer Process Without Initialization: This error occurs when creating a Store instance in renderer process without proper IPC setup:
Error: Electron Store: You need to call `.initRenderer()` from the main process.Solution: Call Store.initRenderer() in main process before creating Store instances in renderer.
IPC Communication Failures: When renderer process cannot communicate with main process:
// Renderer process gets null from IPC call
const appData = electron.ipcRenderer.sendSync('electron-store-get-data');
if (!appData) {
throw new Error('Electron Store: You need to call `.initRenderer()` from the main process.');
}Schema Validation Errors: When data doesn't match defined JSON schema:
Error: Config schema violation: `propertyName` should be stringNote: Validation uses AJV with JSON Schema draft-2020-12
Editor Opening Failures:
When openInEditor() fails to open the storage file:
try {
await store.openInEditor();
} catch (error) {
// Error comes from Electron's shell.openPath()
console.error('Failed to open editor:', error.message);
}File System Errors: Inherited from conf package - file permission issues, disk full, etc.
IPC Channel Name: 'electron-store-get-data' (used for renderer-main communication)
undefined, function, or symbol)set() operations<T> provides compile-time type safety for store data