The Bitwarden Desktop app is built on Electron, which uses a multi-process architecture. Understanding this architecture is critical for developing the desktop app correctly.
Electron Multi-Process Architecture
Electron applications run in two distinct process types:
Main Process
Location: /apps/desktop/src/main/
Entry Point: /apps/desktop/src/main.ts
The main process:
- Runs Node.js with full system access
- Has access to all Electron APIs
- Manages application lifecycle
- Creates and controls browser windows
- Handles native integrations (file system, OS APIs, etc.)
- Cannot import Angular or browser-only code
Key responsibilities:
Renderer Process
Location: /apps/desktop/src/app/
Entry Point: /apps/desktop/src/app/main.ts (Angular bootstrap)
The renderer process:
- Runs Chromium (browser environment)
- Hosts the Angular application
- Has limited system access (sandboxed)
- Cannot directly import Node.js modules
- Cannot directly use Electron main process APIs
Environment: Standard web application with Angular, running in a Chromium-based browser window.
CRITICAL RULE: Never import Node.js modules directly in the renderer process!This will cause runtime errors because Node.js APIs are not available in the browser environment. Use preload scripts or IPC instead.
Preload Scripts
Location: /apps/desktop/src/preload.ts and feature-specific preload files
Preload scripts are the bridge between main and renderer processes. They:
- Run before the renderer process loads
- Have access to both Node.js and browser APIs
- Expose safe APIs to the renderer via
contextBridge
- Are the only way to safely expose Node.js functionality to the renderer
Main Preload Structure
Feature-Specific Preload Example
Inter-Process Communication (IPC)
Electron provides IPC mechanisms for communication between processes:
IPC Invoke (Request-Response)
Best for: Operations that return a value
Renderer → Main:
IPC Send (One-Way)
Best for: Fire-and-forget notifications
Renderer → Main:
IPC Send from Main to Renderer
Main → Renderer:
Context Isolation
Electron uses context isolation for security:
- Renderer process code runs in an isolated context
- Direct access to Electron/Node.js APIs is blocked
- Only APIs explicitly exposed via
contextBridge are available
Never disable context isolation! This is a critical security feature. Always use contextBridge to expose APIs.
Service Architecture
Main Process Services
Services in the main process handle system-level operations:
Renderer Process Services
Angular services in the renderer process:
State Management
State is managed differently in each process:
Main Process State
Renderer Process State
- Angular services and dependency injection
- RxJS for reactive state
- Shared state providers from
@bitwarden/state-internal
Cross-Process State Synchronization
Use IPC to synchronize state:
Native Module Integration
Rust native modules are loaded in the main process only:
See Native Modules for detailed information.
Security Considerations
Principle of Least Privilege
- Renderer process is sandboxed and has minimal privileges
- Main process has full system access
- Only expose necessary APIs through preload scripts
Secure IPC Channels
Process Lifecycle
Application Startup
- Main process starts (
main.ts)
- Services are initialized (storage, crypto, etc.)
- Window is created (
WindowMain)
- Preload script runs (before renderer)
- Renderer process starts (Angular app)
- Angular application bootstraps
- IPC communication established
Application Shutdown
- User triggers quit
- Main process emits
before-quit event
- Cleanup handlers run
- Windows are closed
- Main process exits
Process Communication Patterns
Pattern 1: Simple Request-Response
Pattern 2: Event Broadcasting
Pattern 3: Bidirectional Communication
Critical Development Rules
Main Process Context:
- ✅ Can import Node.js modules
- ✅ Can import Electron main process APIs
- ✅ Can import Rust N-API modules
- ❌ Cannot import Angular modules
- ❌ Cannot import browser-only code
Renderer Process Context:
- ✅ Can import Angular modules
- ✅ Can import browser APIs
- ✅ Can use
window.ipc exposed by preload
- ❌ Cannot import Node.js modules
- ❌ Cannot import Electron APIs directly
- ❌ Cannot import Rust N-API modules directly
Preload Script Context:
- ✅ Can import Electron’s
ipcRenderer and contextBridge
- ✅ Can import Node.js modules
- ✅ Bridge between main and renderer
- ❌ Should not import large libraries
- ❌ Cannot import Angular
Debugging
Main Process
Renderer Process
Use Chrome DevTools (automatically available in development):
IPC Messages
Log IPC messages for debugging: