Agent Skills: Electron + React Best Practices

Guide AI agents through Electron app development with React including security patterns, type-safe IPC, React integration, packaging with code signing, and testing. Keywords: electron, electron-vite, electron-forge, contextBridge, IPC, security, react, packaging, code signing, notarization, playwright, desktop app.

UncategorizedID: jwynia/agent-skills/electron-best-practices

Install this agent skill to your local

pnpm dlx add-skill https://github.com/jwynia/agent-skills/tree/HEAD/skills/tech/development/tooling/electron-best-practices

Skill Files

Browse the full folder contents for electron-best-practices.

Download Skill

Loading file tree…

skills/tech/development/tooling/electron-best-practices/SKILL.md

Skill Metadata

Name
electron-best-practices
Description
"Guide AI agents through Electron app development with React including security patterns, type-safe IPC, React integration, packaging with code signing, and testing. Keywords: electron, electron-vite, electron-forge, contextBridge, IPC, security, react, packaging, code signing, notarization, playwright, desktop app."

Electron + React Best Practices

Guide AI agents in building secure, production-ready Electron applications with React. This skill provides security patterns, type-safe IPC communication, project setup guidance, packaging and code signing workflows, and tools for analysis, scaffolding, and type generation.

When to Use This Skill

Use this skill when:

  • Generating Electron main, preload, or renderer process code
  • Configuring electron-vite or Electron Forge
  • Setting up IPC communication between processes
  • Implementing security patterns (contextBridge, sandbox, CSP)
  • Packaging, signing, and notarizing desktop applications
  • Testing Electron apps with Playwright
  • Designing multi-window architectures

Do NOT use this skill when:

  • Building Tauri apps (different paradigm, use Tauri-specific guidance)
  • Building pure web apps with no desktop requirements
  • Targeting Electron versions below 20 (security defaults differ)
  • Using non-React renderer frameworks (use framework-specific skills)

Core Principles

1. Security First Architecture

Modern Electron security relies on three defaults that became standard in Electron 20+: context isolation, sandbox mode, and nodeIntegration disabled. Disabling any of them allows XSS attacks to escalate to full remote code execution. All main-renderer communication must flow through contextBridge:

// preload.ts - SECURE pattern
contextBridge.exposeInMainWorld('electronAPI', {
  loadPreferences: () => ipcRenderer.invoke('load-prefs'),
  saveFile: (content: string) => ipcRenderer.invoke('save-file', content),
  onUpdateCounter: (callback: (value: number) => void) => {
    const handler = (_event: IpcRendererEvent, value: number) => callback(value);
    ipcRenderer.on('update-counter', handler);
    return () => ipcRenderer.removeListener('update-counter', handler);
  }
});

Set Content Security Policy via HTTP headers for apps loading local files, restricting script sources to 'self'.

2. Type-Safe IPC Communication

The invoke/handle pattern is preferred over send/on for request-response communication, providing proper async/await semantics and error propagation. For typed channels, use a mapped type pattern:

type IpcChannelMap = {
  'load-prefs': { args: []; return: UserPreferences };
  'save-file': { args: [content: string]; return: { success: boolean } };
};

For complex applications, electron-trpc provides full type safety using tRPC's router pattern with Zod validation:

export const appRouter = t.router({
  greeting: t.procedure
    .input(z.object({ name: z.string() }))
    .query(({ input }) => `Hello, ${input.name}!`),
});

Error handling across the IPC boundary requires attention because Electron only serializes the message property of Error objects. Wrap responses in a { success, data, error } result type to preserve full error context.

3. Modern Project Setup

The recommended stack uses electron-vite for development and Electron Forge for packaging. electron-vite provides a unified configuration managing main, preload, and renderer processes with sub-second dev server startup and instant HMR. Electron Forge uses first-party Electron packages for signing and notarization.

src/
├── main/           # Main process (Node.js environment)
│   ├── index.ts
│   └── ipc/        # IPC handlers
├── preload/        # Secure bridge via contextBridge
│   ├── index.ts
│   └── index.d.ts  # TypeScript declarations for exposed APIs
└── renderer/       # React application (pure web, no Node access)
    ├── src/
    └── index.html

4. React Integration Patterns

React 18's concurrent features work normally in Electron's Chromium-based renderer. Strict Mode's double-invocation of effects catches IPC listener leaks that would otherwise cause memory issues. Always return cleanup functions from effects that register IPC listeners:

useEffect(() => {
  const cleanup = window.electronAPI.onUpdateCounter((value) => {
    setCount(value);
  });
  return cleanup;
}, []);

For multi-window applications, the main process should serve as the single source of truth for shared state. Use electron-store for persistence combined with IPC broadcasting so any window's mutation updates all others.

Quick Reference

| Category | Prefer | Avoid | |----------|--------|-------| | Security | contextBridge.exposeInMainWorld() | nodeIntegration: true | | IPC | invoke/handle pattern | send/on for request-response | | Preload | Typed function wrappers | Exposing raw ipcRenderer | | Build tool | electron-vite | webpack-based toolchains | | Packaging | Electron Forge | Manual packaging | | State | Zustand + electron-store | Redux for simple apps | | Testing | Playwright E2E | Spectron (deprecated) | | Updates | electron-updater | Manual update checks | | Signing | CI-integrated code signing | Unsigned releases | | CSP | HTTP headers, 'self' only | No CSP | | Error handling | Result type {success, data, error} | Raw Error across IPC | | Multi-window | Main process as state hub | Direct window-to-window |

Code Generation Guidelines

When generating Electron code, follow these patterns:

BrowserWindow Creation

const win = new BrowserWindow({
  webPreferences: {
    preload: path.join(__dirname, '../preload/index.js'),
    contextIsolation: true,
    sandbox: true,
    nodeIntegration: false,
  },
});

Always enable contextIsolation and sandbox. Never enable nodeIntegration. The preload path must resolve to the built output location.

IPC Handler Module

export function registerFileHandlers(): void {
  ipcMain.handle('save-file', async (_event, content: string) => {
    try {
      await fs.writeFile(filePath, content);
      return { success: true, data: filePath };
    } catch (err) {
      return { success: false, error: (err as Error).message };
    }
  });
}

Group related handlers into modules. Use the result type pattern for all return values. Validate all arguments received from the renderer process.

Common Anti-Patterns

Avoid these patterns when generating Electron code:

| Anti-Pattern | Problem | Solution | |--------------|---------|----------| | nodeIntegration: true | XSS escalates to full RCE | Keep disabled (default) | | Exposing ipcRenderer directly | Full IPC access from renderer | Wrap in contextBridge functions | | Missing contextIsolation | Renderer accesses preload scope | Keep enabled (default since Electron 12) | | No code signing | OS security warnings, Gatekeeper blocks | Sign and notarize for all platforms | | BrowserWindow without sandbox | Preload has full Node.js access | Enable sandbox (default since Electron 20) | | Unvalidated IPC arguments | Injection attacks from renderer | Validate with Zod or manual checks | | 0.0.0.0 server binding | Network-exposed local server | Always bind to 127.0.0.1 | | Missing CSP headers | Script injection vectors | Set strict CSP via HTTP headers | | No IPC error serialization | Lost error context across boundary | Use Result type pattern | | Spectron for testing | Deprecated, Electron 13 max | Use Playwright |

See references/security/security-checklist.md for the full security audit checklist.

Scripts Reference

analyze-security.ts

Analyze Electron projects for security misconfigurations:

deno run --allow-read scripts/analyze-security.ts <path> [options]

Options:
  --strict    Enable all checks
  --json      Output JSON for CI
  -h, --help  Show help

Examples:
  # Analyze a project
  deno run --allow-read scripts/analyze-security.ts ./src

  # Strict mode for CI pipeline
  deno run --allow-read scripts/analyze-security.ts ./src --strict --json

scaffold-electron-app.ts

Scaffold a new Electron + React project with secure defaults:

deno run --allow-read --allow-write scripts/scaffold-electron-app.ts [options]

Options:
  --name <name>     App name (required)
  --path <path>     Target directory (default: ./)
  --with-react      Include React setup
  --with-trpc       Include electron-trpc
  --with-tests      Include Playwright tests

Examples:
  # Basic app with React
  deno run --allow-read --allow-write scripts/scaffold-electron-app.ts \
    --name "my-app" --with-react

  # Full setup with trpc and tests
  deno run --allow-read --allow-write scripts/scaffold-electron-app.ts \
    --name "my-app" --with-react --with-trpc --with-tests

generate-ipc-types.ts

Generate TypeScript type definitions from IPC handler files:

deno run --allow-read --allow-write scripts/generate-ipc-types.ts [options]

Options:
  --handlers <path>  Path to IPC handler files
  --output <path>    Output path for type definitions
  --validate         Validate existing types match handlers

Examples:
  # Generate types from handlers
  deno run --allow-read --allow-write scripts/generate-ipc-types.ts \
    --handlers ./src/main/ipc --output ./src/preload/ipc-types.d.ts

  # Validate types in CI
  deno run --allow-read scripts/generate-ipc-types.ts \
    --handlers ./src/main/ipc --validate

Additional Resources

Security

  • references/security/context-isolation.md - contextBridge and isolation patterns
  • references/security/csp-and-permissions.md - Content Security Policy configuration
  • references/security/security-checklist.md - Full security audit checklist

IPC Communication

  • references/ipc/typed-ipc.md - Typed channel map patterns
  • references/ipc/electron-trpc.md - tRPC integration for full type safety
  • references/ipc/error-serialization.md - Result types across IPC boundary

Architecture

  • references/architecture/project-structure.md - Directory organization
  • references/architecture/process-separation.md - Main, preload, and renderer roles
  • references/architecture/multi-window-state.md - Shared state across windows

React Integration

  • references/integration/react-patterns.md - useEffect cleanup, Strict Mode
  • references/integration/state-management.md - Zustand and electron-store patterns

Packaging & Distribution

  • references/packaging/code-signing.md - Platform-specific signing workflows
  • references/packaging/auto-updates.md - electron-updater configuration
  • references/packaging/bundle-optimization.md - Size reduction techniques
  • references/packaging/ci-cd-patterns.md - GitHub Actions matrix builds

Testing

  • references/testing/playwright-e2e.md - Playwright Electron support
  • references/testing/unit-testing.md - Jest/Vitest multi-project configuration
  • references/testing/test-structure.md - Test organization patterns

Tooling

  • references/tooling/electron-vite.md - Build tool configuration
  • references/tooling/electron-forge.md - Packaging and distribution
  • references/tooling/tauri-comparison.md - When to choose Tauri instead

Templates

  • assets/templates/main-process.ts.md - Main process starter template
  • assets/templates/preload-script.ts.md - Preload script with contextBridge
  • assets/templates/ipc-handler.ts.md - IPC handler module template
  • assets/templates/react-root.tsx.md - React root component template

Configuration Examples

  • assets/configs/electron-vite.config.ts.md - electron-vite configuration
  • assets/configs/forge.config.js.md - Electron Forge configuration
  • assets/configs/tsconfig.json.md - TypeScript configuration presets
  • assets/configs/playwright.config.ts.md - Playwright Electron test config

Complete Examples

  • assets/examples/typed-ipc-example.md - End-to-end typed IPC walkthrough
  • assets/examples/multi-window-example.md - Multi-window state management