Preference System Overview
July 17, 2026 · View on GitHub
The Preference system provides centralized management for user configuration and application settings with cross-window synchronization.
Purpose
PreferenceService handles data that:
- Is a user-modifiable setting that affects app behavior
- Has a fixed key structure with stable value types
- Needs to persist permanently until explicitly changed
- Should sync automatically across all application windows
Key Characteristics
Fixed Key Structure
- Predefined keys in the schema (users modify values, not keys)
- Supports 158 configuration items
- Nested key paths supported (e.g.,
app.theme.mode)
Atomic Values
- Each preference item represents one logical setting
- Values are typically: boolean, string, number, or simple array/object
- Changes are independent (updating one doesn't affect others)
Cross-Window Synchronization
- Changes automatically broadcast to all windows
- Consistent state across main window, quick assistant, etc.
- Conflict resolution handled by Main process
Update Strategies
Optimistic Updates (Default)
// UI updates immediately, then syncs to database
await preferenceService.set("app.theme.mode", "dark");
- Best for: frequent, non-critical settings
- Behavior: Local state updates first, then persists
- Rollback: Automatic revert if persistence fails
Pessimistic Updates
// Waits for database confirmation before updating UI
await preferenceService.set("api.key", "secret", { optimistic: false });
- Best for: critical settings (API keys, security options)
- Behavior: Persists first, then updates local state
- No rollback needed: UI only updates on success
Architecture Diagram
┌─────────────────────────────────────────────────────┐
│ Renderer Process │
│ ┌─────────────────────────────────────────────────┐ │
│ │ usePreference Hook │ │
│ │ - Subscribe to preference changes │ │
│ │ - Optimistic/pessimistic update support │ │
│ └──────────────────────┬──────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ PreferenceService (Renderer) │ │
│ │ - Local cache for fast reads │ │
│ │ - IPC proxy to Main process │ │
│ │ - Subscription management │ │
│ └──────────────────────┬──────────────────────────┘ │
└────────────────────────┼────────────────────────────┘
│ IPC
┌────────────────────────┼────────────────────────────┐
│ Main Process ▼ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ PreferenceService (Main) │ │
│ │ - Full memory cache of all preferences │ │
│ │ - SQLite persistence via Drizzle ORM │ │
│ │ - Cross-window broadcast │ │
│ └──────────────────────┬──────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ SQLite Database (preference table) │ │
│ │ - scope + key structure │ │
│ │ - JSON value storage │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
All Preference_* IPC channels are sender-gated by validateSender (untrusted senders are rejected) — see IpcApi Overview §Security.
Main vs Renderer Responsibilities
Main Process PreferenceService
- Source of truth for all preferences
- Full memory cache for fast access
- SQLite persistence via preference table
- Broadcasts changes to all renderer windows
- Handles batch operations and transactions
Renderer Process PreferenceService
- Local cache for read performance
- Proxies write operations to Main
- Manages React hook subscriptions
- Handles optimistic update rollbacks
- Listens for cross-window updates
Statistics (Debug)
Main process provides getStats(details?) for debugging subscription status:
- Returns total keys, main process subscriptions, and window subscriptions
- Pass
details=truefor per-key breakdown - Warning: Resource-intensive, recommended for development only
import { application } from '@application'
const preferenceService = application.get('PreferenceService')
const stats = preferenceService.getStats(true);
Database Schema
Preferences are stored in the preference table:
// Simplified schema
{
scope: string; // e.g., 'default', 'user'
key: string; // e.g., 'app.theme.mode'
value: json; // The preference value
createdAt: number;
updatedAt: number;
}
Preference Categories
Application Settings
- Theme mode, language, font sizes
- Window behavior, startup options
Feature Toggles
- Show/hide UI elements
- Enable/disable features
User Customization
- Keyboard shortcuts
- Default values for operations
Provider Configuration
- AI provider settings
- API endpoints and tokens
Usage Summary
For detailed code examples and API usage, see Preference Usage Guide.
| Operation | Hook | Service Method |
|---|---|---|
| Read single | usePreference(key) | preferenceService.get(key) |
| Write single | setPreference(value) | preferenceService.set(key, value) |
| Read multiple | usePreferences([...keys]) | preferenceService.getMultiple([...keys]) |
| Write multiple | - | preferenceService.setMultiple({...}) |
Related Documentation
- Preference Schema Guide - Adding new preference keys
- Preference Usage Guide - Hooks and service API