| name | electron-apps |
| description | Electron desktop app development — main/renderer process, IPC, native menus, auto-update, packaging. Use when working with electron apps. |
| domain | development |
| author | oyi77 |
| license | Apache-2.0 |
| subdomain | software-development |
| tags | ["apps","coding","electron","software-engineering","testing"] |
| version | 1.0.0 |
Overview
Electron enables building cross-platform desktop applications using web technologies (HTML, CSS, JavaScript). It powers apps like VS Code, Slack, Discord, and Figma Desktop. The main process handles native APIs while the renderer process runs the web UI.
Capabilities
- Build desktop apps with any web framework (React, Vue, Svelte, vanilla)
- Native menus, system tray, notifications, dialog boxes
- IPC communication between main and renderer processes
- File system access, shell integration, clipboard
- Auto-update with electron-updater
- Deep linking and file associations
- Cross-platform packaging (Windows, macOS, Linux)
- Native Node.js modules support
- Crash reporting and telemetry
When to Use
Trigger phrases:
-
"electron apps"
-
"Electron desktop app development — main/renderer process, IPC, native menus, aut"
-
Need desktop app with rich web UI
-
Already have a web app to package as desktop
-
Need deep OS integration (menus, tray, file associations)
-
Building developer tools or productivity apps
-
Team has strong web development skills
-
Need to support Windows, macOS, and Linux
When NOT to Use
- Task is about deployment, not development (use deploy skills)
- Task is about code review, not writing (use review skills)
- You need to understand existing code first (use research skills)
- Task is about testing only (use test skills)
- Requirements are unclear (clarify first)
- Task is trivially simple (single line fix)
Pseudo Code
The electron-apps workflow follows a standard pipeline pattern.
Core flow:
# electron-apps primary flow
input = prepare(raw_data)
result = process(input, config={apps, auto, desktop, development, electron})
validate(result)
deliver(result)
Error handling:
on error:
log(error_details)
retry_with_backoff(max=3)
if still_failing: alert_and_escalate()
Project Setup
npm create @quick-start/electron my-app
cd my-app
npm install
npm run dev
npm run build
Main Process (main/index.ts)
import { app, BrowserWindow, ipcMain, Menu, Tray, dialog, shell } from 'electron';
import path from 'path';
let mainWindow: BrowserWindow;
let tray: Tray;
function createWindow() {
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
preload: path.join(__dirname, '../preload/index.js'),
contextIsolation: true,
nodeIntegration: false,
},
titleBarStyle: 'hiddenInset',
});
if (process.env.ELECTRON_DEV_URL) {
mainWindow.loadURL(process.env.ELECTRON_DEV_URL);
} else {
mainWindow.loadFile(path.join(__dirname, '../dist/index.html'));
}
}
app.whenReady().then(() => {
createWindow();
createTray();
();
});
() {
tray = (path.(__dirname, ));
contextMenu = .([
{ : , : mainWindow.() },
{ : , : app.() },
]);
tray.();
tray.(contextMenu);
tray.(, mainWindow.());
}
() {
: .[] = [
{
: ,
: [
{ : , : , : openFileDialog },
{ : , : , : saveFile },
{ : },
{ : },
],
},
{
: ,
: [{ : }, { : }, { : }, { : }, { : }],
},
{
: ,
: [{ : }, { : }, { : }],
},
];
.(.(template));
}
IPC Communication
ipcMain.handle('dialog:open', async () => {
const result = await dialog.showOpenDialog(mainWindow, {
properties: ['openFile'],
filters: [{ name: 'Text', extensions: ['txt', 'md', 'json'] }],
});
if (result.canceled) return null;
return fs.readFileSync(result.filePaths[0], 'utf-8');
});
ipcMain.handle('shell:openExternal', async (_, url: string) => {
await shell.openExternal(url);
});
ipcMain.on('window:minimize', () => mainWindow.minimize());
ipcMain.on('window:maximize', () => {
mainWindow.isMaximized() ? mainWindow.unmaximize() : mainWindow.maximize();
});
import { contextBridge, ipcRenderer } from 'electron';
contextBridge.exposeInMainWorld('electronAPI', {
: ipcRenderer.(),
: ipcRenderer.(, url),
: ipcRenderer.(),
: ipcRenderer.(),
: {
ipcRenderer.(, (value));
},
});
content = ..();
..();
Auto Update
import { autoUpdater } from 'electron-updater';
autoUpdater.autoDownload = false;
autoUpdater.autoInstallOnAppQuit = true;
autoUpdater.on('update-available', async (info) => {
const { response } = await dialog.showMessageBox({
type: 'info',
buttons: ['Download', 'Later'],
title: 'Update Available',
message: `Version ${info.version} is available. Download now?`,
});
if (response === 0) autoUpdater.downloadUpdate();
});
autoUpdater.on('update-downloaded', async () => {
const { response } = await dialog.showMessageBox({
type: 'info',
buttons: ['Restart', 'Later'],
title: 'Update Ready',
message: 'Update downloaded. Restart to apply?',
});
if (response === 0) autoUpdater.quitAndInstall();
});
app.whenReady().then(() => {
createWindow();
autoUpdater.();
});
Packaging (electron-builder)
{
"build": {
"appId": "com.example.myapp",
"productName": "My App",
"mac": {
"category": "public.app-category.developer-tools",
"target": ["dmg", "zip"],
"icon": "build/icon.icns"
},
"win": {
"target": ["nsis", "portable"],
"icon": "build/icon.ico"
},
"linux": {
"target": ["AppImage", "deb"
npm run build
npx electron-builder --mac
npx electron-builder --win
npx electron-builder --linux
Error Handling
| Error | Cause | Fix |
|---|
Cannot find module | Native module not rebuilt | npx electron-rebuild |
SecurityError: blocked | Context isolation blocking API | Use preload script with contextBridge |
GPU process error | GPU rendering issue | Add app.disableHardwareAcceleration() |
Auto-update failed | No publish config or signing | Check build.publish config |
Code signing failed | Missing certificates | Set CSC_LINK and CSC_KEY_PASSWORD env vars |
Common Patterns
Proven patterns for electron-apps usage.
- Batch processing: Process multiple items in parallel for throughput
- Retry with backoff: Handle transient failures gracefully
- Rate limiting: Respect API limits with configurable delays
- Logging: Structured logging for debugging and audit trails
Store (Persistent Settings)
import Store from 'electron-store';
const store = new Store({
defaults: { theme: 'dark', windowBounds: { width: 1200, height: 800 } },
});
mainWindow.on('resize', () => {
store.set('windowBounds', mainWindow.getBounds());
});
const bounds = store.get('windowBounds');
mainWindow.setBounds(bounds);
Protocol Handler (Deep Links)
app.setAsDefaultProtocolClient('myapp');
app.on('open-url', (_, url) => {
handleDeepLink(url);
});
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
} else {
app.on('second-instance', (_, argv) => {
const url = argv.find(arg => arg.startsWith('myapp://'));
if (url) handleDeepLink(url);
});
}
Crash Reporting
import { crashReporter } from 'electron';
crashReporter.start({
productName: 'My App',
submitURL: 'https://your-crash-server.com/submit',
uploadToServer: true,
});
How to Use
- Understand the requirement and existing codebase patterns
- Design the solution with error handling and testability in mind
- Implement incrementally with tests for each change
- Verify against expected outcomes (manual and automated)
- Document usage, edge cases, and integration points
- Review with team before merging to shared branches
Red Flags
- Skipping tests to ship faster: Untested code breaks in production when you least expect it
- No error handling in production code: Unhandled errors crash services and lose user data
- Hardcoded configuration values: Hardcoded values prevent environment switching and leak secrets
- Ignoring security implications: Missing input validation, auth bypasses, and injection vulnerabilities
- Over-engineering simple solutions: Premature abstraction adds complexity without proportional benefit
Verification
Process
- Analyze the task requirements
- Apply domain expertise
- Verify output quality
Anti-Rationalization Table
| Rationalization | Reality |
|---|
| "Tests slow me down" | Bugs slow you down 10x more. Tests are speed, not overhead. |
| "I will refactor later" | Technical debt compounds. Refactor as you go. |
| "It works on my machine" | If it is not in CI, it does not work. Ship proof, not claims. |