electron

Cross-platform desktop applications with web technologies (Chromium + Node.js)

SKILL.md

GitHub

Electron

Framework for building cross-platform desktop applications using Chromium and Node.js. Ships a single codebase as native apps for macOS, Windows, and Linux.

When to Use

  • Desktop apps needing OS-level access (file system, tray, notifications)
  • Wrapping an existing web app as a native desktop experience
  • Offline-first apps with local data storage
  • Cross-platform tools where native UI per-platform is not justified

Key Patterns

Main vs Renderer Process — Main process (Node.js) manages windows, system APIs, and app lifecycle. Renderer processes (Chromium) handle UI. Never run privileged code in the renderer.

IPC Communication — Use contextBridge.exposeInMainWorld() in preload scripts to expose APIs safely. Communicate via ipcMain.handle() / ipcRenderer.invoke() (async) or ipcMain.on() / ipcRenderer.send() (fire-and-forget).

Security Model — Always enable contextIsolation: true and sandbox: true. Never set nodeIntegration: true in production. Validate all IPC inputs in main process. Use safeStorage for sensitive data.

BrowserWindow Configuration — Set webPreferences.preload to a dedicated preload script. Use minWidth/minHeight for sizing constraints. Enable titleBarStyle: 'hiddenInset' on macOS for frameless look.

Auto-Update — Use electron-updater with autoUpdater.checkForUpdatesAndNotify(). Publish to GitHub Releases or a private feed. Sign builds for macOS (notarization) and Windows (code signing).

Tray & Menu System — Create Tray in main process. Build menus with Menu.buildFromTemplate(). Use nativeImage for icons.

Native File System — Use dialog.showOpenDialog() / dialog.showSaveDialog() from main process, exposed via IPC. Never give renderer direct fs access.

Packaging (electron-builder) — Configure in package.json or electron-builder.yml. Target dmg+zip (macOS), nsis (Windows), AppImage+deb (Linux). Use files array to control included resources.

Protocol Handlers — Register custom protocols with protocol.handle('app', handler) for loading local resources securely instead of file:// URLs.

Context Isolation — Always pair contextIsolation: true with a preload script. The preload runs in an isolated context with access to Node.js APIs but exposes only explicit bindings to the renderer.

Anti-Patterns

Anti-Pattern Why It's Bad Fix
nodeIntegration: true RCE via XSS Use preload + contextBridge
Bundling unused locales +40MB app size Exclude via electron-builder config
Synchronous IPC (sendSync) Blocks renderer, freezes UI Use async invoke/handle
No code signing OS warnings, update fails Sign + notarize all builds
Single BrowserWindow for all Memory bloat, no isolation Separate windows for heavy features
Secrets in renderer Exposed via DevTools Use safeStorage in main process