Back to Home

Electron Guide - Cross-Platform Desktop Apps

Getting Started with Electron

Your journey from web developer to desktop app builder starts here. Learn to think in terms of processes, security boundaries, and native integration.

The Mental Model Shift

If you're coming from web development, Electron will feel both familiar and foreign. You'll write React components and style with CSS—but you'll also think about process architecture, native APIs, and security boundaries that don't exist in browser-based apps.

Here's the shift: A web app runs in a single process with sandboxed limitations. An Electron app runs in multiple processes—one with full system access (main process) and others running your UI (renderer processes). This separation is intentional: security.

Think of it like building a client-server app, except both the client and server run on the same machine. The main process is your "backend" with database access (file system), and renderers are your "frontend" displaying UI. They communicate through IPC (Inter-Process Communication), just like HTTP requests.

Setting Up Your Environment

The good news: if you can build web apps, you already have most of what you need. Electron runs on Node.js, so your existing JavaScript/TypeScript knowledge transfers directly. The learning curve isn't the language—it's understanding the architecture.

Prerequisites

  • Node.js v18+ - The runtime that powers Electron
  • npm or yarn - Package management
  • VS Code - Best IDE for TypeScript + Electron debugging
  • Basic TypeScript knowledge - Type safety is crucial for multi-process apps

# Verify your setup

node --version # v18.0.0 or higher

The Fast Path: Electron Forge

Electron Forge is the official scaffolding tool. It's opinionated (in a good way) and sets up everything you need: TypeScript, webpack, hot reload, and build tools. When I started VibeBlaster, I used Forge and never looked back.

Why Forge over manual setup? Because desktop app development has unique requirements: code signing, auto-updates, platform-specific builds, and installer generation. Forge handles all of this with sane defaults.

npm create electron-app@latest my-app -- --template=typescript-webpack

# This creates a production-ready structure with:

# ✓ TypeScript configured

# ✓ Webpack for bundling

# ✓ Hot reload enabled

# ✓ Build tools ready

💡 Pro Tip: Start with the typescript-webpack template. It includes everything you'll eventually need. Trust me—adding TypeScript and webpack to an existing Electron app later is painful.

Understanding the Structure

An Electron app isn't a single JavaScript file—it's an orchestrated system of processes working together. Understanding this structure is crucial because it informs every architectural decision you'll make.

my-electron-app/
├── src/
│   ├── main/
│   │   └── index.ts           # Main process (Node.js runtime)
│   ├── preload/
│   │   └── index.ts           # Security bridge
│   └── renderer/
│       ├── index.html         # UI entry point
│       ├── App.tsx            # React app (or your framework)
│       └── index.tsx          # Renderer bootstrap
├── package.json
├── tsconfig.json
└── forge.config.ts            # Build configuration

Main Process

Your "backend." Runs in Node.js with full system access. Creates windows, handles file I/O, manages app lifecycle.

Think: Express server, but for desktop

Renderer Process

Your "frontend." Runs in Chromium, sandboxed for security. Each window is a separate renderer process.

Think: React app in a browser tab

Preload Script

The secure bridge. Exposes carefully chosen APIs from main to renderer without breaking sandboxing.

Think: API gateway with CORS policies

⚠️ Critical Security Concept

Renderer processes should NEVER have direct access to Node.js APIs. This is intentional—if a renderer is compromised (XSS attack, malicious npm package, etc.), the attacker shouldn't get system access. The preload script acts as a controlled gateway, exposing only safe, validated APIs.

Your First Meaningful App

Instead of "Hello World," let's build something you'll actually understand: a simple note-taking app. It'll demonstrate the three-part architecture, IPC communication, and file system access—the foundation of every Electron app you'll ever build.

What We're Building

A desktop notes app that:

  • Saves notes to disk (main process handles file I/O)
  • Displays a UI (renderer process shows the interface)
  • Communicates securely (preload script bridges the two)

This demonstrates the core pattern you'll use in every Electron app: renderer requests data, main process handles privileged operations, data flows back through secure channels.

The Main Process: Your Backend

The main process creates windows and handles system operations. Here's the conceptual flow:

1

App Initialization

Wait for Electron to be ready, then create the main window

2

Window Configuration

Set size, load HTML, configure security (context isolation, no Node.js in renderer)

3

IPC Handlers

Register handlers for renderer requests (save-note, load-note, etc.)

4

File System Operations

Handle reading/writing notes to disk (privileged operation)

The Preload Script: Secure Bridge

This is where security happens. The preload script runs in a special context with access to both Node.js and the renderer's window object—but it exposes ONLY the APIs you explicitly allow.

The Pattern:

contextBridge creates a safe channel

exposeInMainWorld adds APIs to window

ipcRenderer.invoke calls main process handlers

Renderer never touches Node.js directly, ever

The Renderer: Your UI

This is familiar territory—React, Vue, or vanilla JS. The only difference: instead of calling an HTTP API, you call the APIs exposed by your preload script.

The mental model:

// Web app pattern:

await fetch('/api/notes')

// Electron app pattern:

await window.electronAPI.loadNotes()

Same concept, different transport. Instead of HTTP, you're using IPC.

💡 VibeBlaster Example

In VibeBlaster, the renderer displays OAuth login buttons. When clicked, it callswindow.api.startOAuthFlow('twitter'). The main process opens a secure browser window, handles the OAuth callback, stores tokens securely, and returns success to the renderer. The renderer never sees the tokens or opens windows—it just requests the operation through the secure bridge.

Development Workflow: Why It Matters

Electron development feels surprisingly like web development because of hot reload. Change code, see results instantly—no full rebuild. This is critical when you're iterating on UI or debugging IPC communication.

Hot Reload (Renderer)

Changes to your UI (HTML, CSS, React components) refresh automatically. Just like Create React App or Vite.

Why: Your renderer is just a web page running in Chromium

Manual Restart (Main)

Changes to main process code require restarting the entire app. Electron Forge handles this, but expect a 2-3 second delay.

Why: Main process is Node.js, not hot-reloadable

Development Commands

npm startorelectron-forge start

Launches your app with DevTools enabled. This is your daily driver during development.

npm run package

Creates a distributable version for your current platform (no installer). Useful for testing the packaged version before distribution.

npm run make

Creates platform-specific installers (.dmg for Mac, .exe for Windows, .deb for Linux). This is what you distribute to users.

🛠️ Real-World Workflow (VibeBlaster)

Daily development: npm start and keep it running. UI changes show instantly, main process changes restart the app automatically.

Testing OAuth flows: Use npm run packageto test the production-like version (OAuth redirect URIs behave differently in dev vs. production).

Pre-release testing: npm run make to generate the installer, install it locally, and test the full user experience including auto-updates.

Pro Tip: DevTools are Your Friend

Electron's DevTools work exactly like Chrome DevTools. You can inspect the renderer process (your UI), set breakpoints, monitor network requests, and debug React components with React DevTools.

For the main process, use console.log()or attach a debugger via VS Code's launch configuration. Main process logs appear in your terminal, not the app window.

Ready for the Deep Dive?

You've seen the three-part architecture in action and understand the mental model. Now it's time to understand why Electron works this way—and how to design your app's architecture around these constraints.

In the next chapter, you'll learn:

  • Why multi-process? The security and performance reasons behind the architecture
  • IPC patterns: When to use invoke/handle vs. send/on, and why it matters
  • Security boundaries: Where XSS and injection attacks can happen, and how to prevent them
  • Real-world architecture: How VibeBlaster structures main process modules and IPC handlers

This is where you'll move from "it works" to "I understand why it works this way"—which is when you start making better architectural decisions.