| name | electron-apps |
| description | Electron desktop app development across macOS and Windows. Including security, performance, using code beyond Javascript & Typescript, native APIs, storage, debugging and troubleshooting issues, storage, and electron best practices. Use when working with electron code, troubleshooting, testing, preparing for release. |
Electron Apps
Build production-grade desktop applications with Electron. TypeScript throughout, security-first, performance-aware.
Quick Start
npx create-electron-app@latest my-app --template=vite-typescript
cd my-app && bun install && npm run start
For project layout, IPC contracts, and secure window creation, see Project Setup.
Essential Patterns
Secure BrowserWindow
Every window starts here. These are Electron 20+ defaults — never weaken them without a specific reason:
const win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false,
sandbox: true,
},
show: false,
});
win.once('ready-to-show', () => win.show());
Module Loading Strategy
require() is synchronous and recursive — the single biggest startup bottleneck. Bundle everything; load progressively.
import heavyModule from 'heavy-module';
const getHeavy = () => import('heavy-module');
const Settings = lazy(() => import('./pages/Settings'));
One bundle per process: main.bundle.js, preload.bundle.js, renderer.bundle.js (with chunk splitting). Details in Bundling.
Unblocking the Main Process
The main process is the control tower. Blocking it freezes every window.
const data = fs.readFileSync('large.json', 'utf-8');
const data = await fs.promises.readFile('large.json', 'utf-8');
const result = ipcRenderer.sendSync('query', args);
const result = await ipcRenderer.invoke('query', args);
const child = utilityProcess.fork(path.join(__dirname, 'worker.js'));
child.postMessage(payload);
See Unblocking for Web Workers, Worker↔Main direct channels, and utilityProcess.
Cache-First Rendering
Desktop apps should feel instant on repeat launches. Render from local cache, refresh in background:
const queryClient = new QueryClient({
defaultOptions: { queries: { gcTime: 1000 * 60 * 60 * 24 } },
});
For optimistic updates, prefetching, and pre-warmed startup (Linear-style), see Cache-First.
IPC Contract
Define channel names once, share between main and preload:
export const IPC = {
GET_VERSION: 'get-version',
SAVE_FILE: 'save-file',
} as const;
For the full invoke/handle pattern, listener cleanup, and MessagePort for high-throughput, see IPC Patterns.
Reference Map
Core Concepts
- Process Model — main process, renderer, preload scripts, TypeScript declarations
- IPC Patterns — invoke/handle, one-way, main→renderer, renderer↔renderer, MessagePort, listener cleanup
Security
Performance
- Unblocking Processes — main process rules, renderer optimization, Web Workers, Worker↔Main direct channels, startup optimization, V8 snapshots, long-running app concerns
- Bundling & Code Splitting — require() problem, one-bundle-per-process, code splitting, tree shaking, Bun (pkg mgr vs bundler), CSP implications
- Native Code & WASM — WebAssembly, NAPI-RS (Rust 10x case study), Go bindings, Python sidecars, comparison table
- Cache-First & Perceived Performance — pre-warmed startup, IndexedDB+TanStack persistence, optimistic updates, prefetch, idle-time work
- Instrumentation & Profiling — Chrome DevTools, contentTracing API, CPU instruction counting, production monitoring (Slack/VSCode patterns), component-level CPU costs, React profiling tools
Windows & UI
- Window Management — custom title bars, traffic lights, frameless/transparent windows, drag regions, vibrancy, progress bars, multi-window patterns, navigation history, prevent-close dialogs
Patterns & Recipes
- Recipes — keyboard shortcuts (local/global/window), deep links (custom protocol), notifications, spellchecker, device access (Bluetooth/HID/Serial), offscreen rendering, multithreading options, background server pattern, live reloading, Windows taskbar, environment variables
Debugging
- Debugging — main process inspector, renderer DevTools, REPL, DevTools extensions, native addon debugging (Xcode/lldb), automated testing with Playwright, common debug techniques
Native & Platform
- Platform Integration — device access (screen, camera, mic, clipboard), power monitoring, startup registration, storage paradigms, network interception, safe key storage, macOS (Swift sidecars, permissions, dock), Windows (taskbar, jump lists), native UI (menus, tray, notifications, theme)
Electron Forge
- Config & Plugins — build lifecycle, TypeScript config, packagerConfig, rebuildConfig, plugin system (Vite/Fuses), hooks, build identifiers, CLI commands
- Makers & Distribution — all makers (DMG/Squirrel/deb/AppX/WiX), publishers (GitHub/S3), code signing (macOS/Windows), notarization, auto-updates, CI/CD, custom makers/publishers
Project Setup
- Structure & Setup — recommended directory layout, Forge+Vite+TS quick start, Bun integration, IPC channel contracts, tsconfig, essential dependencies, secure BrowserWindow factory
Decision Quick-Reference
| Need | Solution |
|---|
| Background task (non-UI) | utilityProcess |
| Background task (renderer-bound) | Web Worker |
| Heavy computation | NAPI-RS (Rust) or WASM |
| Data persistence | IndexedDB (cache), SQLite (structured), safeStorage (secrets), electron-store (config) |
| IPC pattern | invoke/handle (default), send/on (fire-forget), MessagePort (high-throughput) |
| Custom title bar | titleBarStyle: 'hidden' + HTML/CSS with app-region: drag |
| System-wide shortcut | globalShortcut.register() |
| Deep link | app.setAsDefaultProtocolClient() |
| Testing | Playwright (E2E), Jest (unit), contentTracing (perf regression) |