EL

electron-development

Build secure, production-grade cross-platform desktop applications using Electron.

Install

mkdir -p .claude/skills/electron-development && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/18386" && unzip -o skill.zip -d .claude/skills/electron-development && rm skill.zip

Installs to .claude/skills/electron-development

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Master Electron desktop app development with secure IPC, contextIsolation, preload scripts, multi-process architecture, electron-builder packaging, code signing, and auto-update.
178 charsno explicit “when” trigger
Advanced

Key capabilities

  • Build new Electron desktop applications
  • Secure Electron apps with `contextIsolation`, `sandbox`, `CSP`
  • Set up IPC communication between main, renderer, and preload processes
  • Package and distribute Electron apps with `electron-builder`
  • Implement auto-update with `electron-updater`
  • Integrate native OS features (menus, tray, notifications)

How it works

The skill guides Electron development by enforcing security defaults, designing IPC channels through preload scripts, and structuring projects for multi-process architecture. It covers packaging, code signing, and auto-update strategies.

Inputs & outputs

You give it
Request for an Electron desktop application feature or architecture setup
You get back
Electron application code with secure IPC, process model setup, and packaging configuration

When to use electron-development

  • Building a cross-platform desktop app
  • Securing Electron IPC
  • Packaging and signing Electron apps

About this skill

Electron Development

You are a senior Electron engineer specializing in secure, production-grade desktop application architecture. You have deep expertise in Electron's multi-process model, IPC security patterns, native OS integration, application packaging, code signing, and auto-update strategies.

Use this skill when

  • Building new Electron desktop applications from scratch
  • Securing an Electron app (contextIsolation, sandbox, CSP, nodeIntegration)
  • Setting up IPC communication between main, renderer, and preload processes
  • Packaging and distributing Electron apps with electron-builder or electron-forge
  • Implementing auto-update with electron-updater
  • Debugging main process issues or renderer crashes
  • Managing multiple windows and application lifecycle
  • Integrating native OS features (menus, tray, notifications, file system dialogs)
  • Optimizing Electron app performance and bundle size

Do not use this skill when

  • Building web-only applications without desktop distribution → use react-patterns, nextjs-best-practices
  • Building Tauri apps (Rust-based desktop alternative) → use tauri-development if available
  • Building Chrome extensions → use chrome-extension-developer
  • Implementing deep backend/server logic → use nodejs-backend-patterns
  • Building mobile apps → use react-native-architecture or flutter-expert

Instructions

  1. Analyze the project structure and identify process boundaries.
  2. Enforce security defaults: contextIsolation: true, nodeIntegration: false, sandbox: true.
  3. Design IPC channels with explicit whitelisting in the preload script.
  4. Implement, test, and build with appropriate tooling.
  5. Validate against the Production Security Checklist before shipping.

Core Expertise Areas

1. Project Structure & Architecture

Recommended project layout:

my-electron-app/
├── package.json
├── electron-builder.yml        # or forge.config.ts
├── src/
│   ├── main/
│   │   ├── main.ts             # Main process entry
│   │   ├── ipc-handlers.ts     # IPC channel handlers
│   │   ├── menu.ts             # Application menu
│   │   ├── tray.ts             # System tray
│   │   └── updater.ts          # Auto-update logic
│   ├── preload/
│   │   └── preload.ts          # Bridge between main ↔ renderer
│   ├── renderer/
│   │   ├── index.html          # Entry HTML
│   │   ├── App.tsx             # UI root (React/Vue/Svelte/vanilla)
│   │   ├── components/
│   │   └── styles/
│   └── shared/
│       ├── constants.ts        # IPC channel names, shared enums
│       └── types.ts            # Shared TypeScript interfaces
├── resources/
│   ├── icon.png                # App icon (1024x1024)
│   └── entitlements.mac.plist  # macOS entitlements
├── tests/
│   ├── unit/
│   └── e2e/
└── tsconfig.json

Key architectural principles:

  • Separate entry points: Main, preload, and renderer each have their own build configuration.
  • Shared types, not shared modules: The shared/ directory contains only types, constants, and enums — never executable code imported across process boundaries.
  • Keep main process lean: Main should orchestrate windows, handle IPC, and manage app lifecycle. Business logic belongs in the renderer or dedicated worker processes.

2. Process Model (Main / Renderer / Preload / Utility)

Electron runs multiple processes that are isolated by design:

ProcessRoleNode.js AccessDOM Access
MainApp lifecycle, windows, native APIs, IPC hub✅ Full❌ None
RendererUI rendering, user interaction❌ None (by default)✅ Full
PreloadSecure bridge between main and renderer✅ Limited (via contextBridge)✅ Before page loads
UtilityCPU-intensive tasks, background work✅ Full❌ None

BrowserWindow with security defaults (MANDATORY):

import { BrowserWindow } from 'electron';
import path from 'node:path';

function createMainWindow(): BrowserWindow {
  const win = new BrowserWindow({
    width: 1200,
    height: 800,
    webPreferences: {
      // ── SECURITY DEFAULTS (NEVER CHANGE THESE) ──
      contextIsolation: true,     // Isolates preload from renderer context
      nodeIntegration: false,     // Prevents require() in renderer
      sandbox: true,              // OS-level process sandboxing
      
      // ── PRELOAD SCRIPT ──
      preload: path.join(__dirname, '../preload/preload.js'),
      
      // ── ADDITIONAL HARDENING ──
      webSecurity: true,          // Enforce same-origin policy
      allowRunningInsecureContent: false,
      experimentalFeatures: false,
    },
  });

  // Content Security Policy
  win.webContents.session.webRequest.onHeadersReceived((details, callback) => {
    callback({
      responseHeaders: {
        ...details.responseHeaders,
        'Content-Security-Policy': [
          "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:;"
        ],
      },
    });
  });

  return win;
}

⚠️ CRITICAL: Never set nodeIntegration: true or contextIsolation: false in production. These settings expose the renderer to remote code execution (RCE) attacks through XSS vulnerabilities.


3. Secure IPC Communication

IPC is the only safe channel for communication between main and renderer processes. All IPC must flow through the preload script.

Preload script (contextBridge + explicit whitelisting):

// src/preload/preload.ts
import { contextBridge, ipcRenderer } from 'electron';

// ── WHITELIST: Only expose specific channels ──
const ALLOWED_SEND_CHANNELS = [
  'file:save',
  'file:open',
  'app:get-version',
  'dialog:show-open',
] as const;

const ALLOWED_RECEIVE_CHANNELS = [
  'file:saved',
  'file:opened',
  'app:version',
  'update:available',
  'update:progress',
  'update:downloaded',
  'update:error',
] as const;

type SendChannel = typeof ALLOWED_SEND_CHANNELS[number];
type ReceiveChannel = typeof ALLOWED_RECEIVE_CHANNELS[number];

contextBridge.exposeInMainWorld('electronAPI', {
  // One-way: renderer → main
  send: (channel: SendChannel, ...args: unknown[]) => {
    if (ALLOWED_SEND_CHANNELS.includes(channel)) {
      ipcRenderer.send(channel, ...args);
    }
  },

  // Two-way: renderer → main → renderer (request/response)
  invoke: (channel: SendChannel, ...args: unknown[]) => {
    if (ALLOWED_SEND_CHANNELS.includes(channel)) {
      return ipcRenderer.invoke(channel, ...args);
    }
    return Promise.reject(new Error(`Channel "${channel}" is not allowed`));
  },

  // One-way: main → renderer (subscriptions)
  on: (channel: ReceiveChannel, callback: (...args: unknown[]) => void) => {
    if (ALLOWED_RECEIVE_CHANNELS.includes(channel)) {
      const listener = (_event: Electron.IpcRendererEvent, ...args: unknown[]) => callback(...args);
      ipcRenderer.on(channel, listener);
      return () => ipcRenderer.removeListener(channel, listener);
    }
    return () => {};
  },
});

Main process IPC handlers:

// src/main/ipc-handlers.ts
import { ipcMain, dialog, BrowserWindow } from 'electron';
import { readFile, writeFile } from 'node:fs/promises';

export function registerIpcHandlers(): void {
  // invoke() pattern: returns a value to the renderer
  ipcMain.handle('file:open', async () => {
    const { canceled, filePaths } = await dialog.showOpenDialog({
      properties: ['openFile'],
      filters: [{ name: 'Text Files', extensions: ['txt', 'md'] }],
    });
    
    if (canceled || filePaths.length === 0) return null;
    
    const content = await readFile(filePaths[0], 'utf-8');
    return { path: filePaths[0], content };
  });

  ipcMain.handle('file:save', async (_event, filePath: string, content: string) => {
    // VALIDATE INPUTS — never trust renderer data blindly
    if (typeof filePath !== 'string' || typeof content !== 'string') {
      throw new Error('Invalid arguments');
    }
    await writeFile(filePath, content, 'utf-8');
    return { success: true };
  });

  ipcMain.handle('app:get-version', () => {
    return process.versions.electron;
  });
}

Renderer usage (type-safe):

// src/renderer/App.tsx — or any renderer code
// The electronAPI is globally available via contextBridge

declare global {
  interface Window {
    electronAPI: {
      send: (channel: string, ...args: unknown[]) => void;
      invoke: (channel: string, ...args: unknown[]) => Promise<unknown>;
      on: (channel: string, callback: (...args: unknown[]) => void) => () => void;
    };
  }
}

// Open a file via IPC
async function openFile() {
  const result = await window.electronAPI.invoke('file:open');
  if (result) {
    console.log('File content:', result.content);
  }
}

// Subscribe to updates from main process
const unsubscribe = window.electronAPI.on('update:available', (version) => {
  console.log('Update available:', version);
});

// Cleanup on unmount
// unsubscribe();

IPC Pattern Summary:

PatternMethodUse Case
Fire-and-forgetipcRenderer.send()ipcMain.on()Logging, telemetry, non-critical notifications
Request/ResponseipcRenderer.invoke()ipcMain.handle()File operations, dialogs, data queries
Push to rendererwebContents.send()ipcRenderer.on()Progress updates, download status, auto-update

⚠️ Never use ipcRenderer.sendSync() in production — it blocks the renderer's event loop and freezes the UI.


4. Security Hardening

Production Security Checklist

── MANDATORY ──
[ ] contextIsolation: true
[ ] nodeIntegration: false
[ ] sandbox: true
[ ] webSecurity: true
[ ] allowRunningInsecureContent: false

── IPC ──
[ ] Preload uses contextBridge with explicit channel whitelisting
[ ] All IPC inputs are validated in the main process
[ ] No raw ipcRenderer exposed to renderer context


---

*Content truncated.*

When not to use it

  • When building web-only applications
  • When building Tauri apps
  • When building Chrome extensions

Limitations

  • Electron bundles Chromium + Node.js, resulting in a minimum ~150MB app size
  • Not suitable for apps where minimal install size is critical (consider Tauri instead)
  • Single-window apps are simpler to architect; multi-window state synchronization requires careful IPC design

How it compares

This skill focuses on secure, production-grade Electron architecture by mandating specific security defaults like `contextIsolation: true` and `nodeIntegration: false`, and detailing the multi-process model, which is more specialized than g

Compared to similar skills

electron-development side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
electron-development (this skill)03moReviewAdvanced
web-development51moNo flagsIntermediate
fullstack-guardian12moNo flagsAdvanced
apollo-prod-checklist110dCautionIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry