Skip to main content
This guide covers how to build the Bitwarden Desktop application for different platforms.

Prerequisites

  • Node.js (version specified in .nvmrc)
  • Rust toolchain (for native modules)
  • Platform-specific tools:
    • Windows: Visual Studio Build Tools
    • macOS: Xcode Command Line Tools
    • Linux: Build essentials, depending on your distribution

Build Commands

Development Build

Build all components (main, renderer, and preload) in development mode:
npm run build:dev
This runs three builds concurrently:
  • Main process: npm run build:main:dev
  • Renderer process: npm run build:renderer:dev
  • Preload script: npm run build:preload:dev

Production Build

Build all components in production mode:
npm run build
This is equivalent to:
concurrently \
  "npm run build:main" \
  "npm run build:renderer" \
  "npm run build:preload"

Individual Component Builds

Main Process

# Production
npm run build:main

# Development
npm run build:main:dev

# Development with watch mode
npm run build:main:watch

Renderer Process (Angular)

# Production
npm run build:renderer

# Development
npm run build:renderer:dev

# Development with watch mode
npm run build:renderer:watch

Preload Script

# Production
npm run build:preload

# Development
npm run build:preload:dev

# Development with watch mode
npm run build:preload:watch

Native Module Build

Build the Rust native modules:
# Cross-platform build
npm run build-native

# macOS with autofill provider
npm run build-native-macos
The native modules are located in desktop_native/ and built using N-API.

Platform-Specific Builds

Windows

Standard Build

Build for all Windows architectures (x64, ARM64, ia32):
npm run dist:win
This combines:
  1. npm run build - Build all TypeScript/Angular code
  2. npm run pack:win - Package with electron-builder
Or for CI environments:
npm run dist:win:ci

Beta Channel

npm run pack:win:beta
Uses electron-builder.beta.json configuration.
Windows builds create multiple installer formats: NSIS installer, portable executable, and Microsoft Store package.

macOS

Standard Build (Universal Binary)

Build for both Intel and Apple Silicon:
npm run dist:mac
This creates a universal binary that runs natively on both architectures.

With macOS Autofill Extension

npm run pack:mac:with-extension
This:
  1. Builds the autofill provider: ./desktop_native/autofill_provider/build.sh
  2. Creates the macOS extension: npm run build:macos-extension:mac
  3. Packages the app: electron-builder --mac --universal

Mac App Store (MAS)

# Production MAS build
npm run dist:mac:mas

# Development MAS build
npm run dist:mac:masdev

# Local MAS build (no provisioning profiles)
npm run pack:local:mac
Mac App Store builds require:
  • Valid Apple Developer account
  • Provisioning profiles
  • Proper entitlements configuration
  • Code signing certificates
The MAS build process differs from standard macOS builds due to sandboxing requirements.

Publishing to Mac App Store

npm run publish:mac:mas
This builds the app and uploads it using xcrun altool:
xcrun altool --upload-app --type osx \
  --file "$(find ./dist/mas-universal/Bitwarden*.pkg)" \
  --apiKey $APP_STORE_CONNECT_AUTH_KEY \
  --apiIssuer $APP_STORE_CONNECT_TEAM_ISSUER

Linux

Standard Build (x64)

npm run dist:lin
This creates:
  • Snap package (with polkit policy)
  • AppImage
  • tar.gz archive
  • Unpacked directory with resources

ARM64 Build

npm run dist:lin:arm64

Flatpak

Development flatpak:
npm run flatpak:dev
Production flatpak:
npm run pack:lin:flatpak
The Linux build process includes special handling for:
  • Snap packages: Adds polkit policy to meta/polkit/
  • Flatpak: Uses manifest from resources/com.bitwarden.desktop.devel.yaml
  • Desktop files and icons for proper integration

Running the App

Development Mode

# Start with dev environment
npm run electron

# Start with certificate error ignoring (for testing)
npm run electron:ignore

Production Mode

npm run start
This sets:
  • ELECTRON_IS_DEV=0
  • ELECTRON_NO_UPDATER=1
  • Runs from ./build directory

Publishing

Publish builds to distribution servers:
# Linux
npm run publish:lin

# macOS
npm run publish:mac

# Windows
npm run publish:win

# Windows (dev build)
npm run publish:win:dev
Publishing commands use electron-builder with -p always flag, which uploads to configured publish targets. Ensure proper credentials are configured before running these commands.

Build Configuration

Webpack Configuration

The app uses webpack with three separate configurations:
// Main process
NODE_ENV=production webpack --config webpack.config.js --config-name main

// Renderer process
NODE_ENV=production webpack --config webpack.config.js --config-name renderer

// Preload script
NODE_ENV=production webpack --config webpack.config.js --config-name preload

Environment Variables

  • NODE_ENV: production or development
  • ELECTRON_IS_DEV: 0 or 1
  • ELECTRON_NO_UPDATER: Disable auto-updater
  • BITWARDEN_APPDATA_DIR: Custom app data directory
  • PORTABLE_EXECUTABLE_DIR: Windows portable mode

macOS Extension Build Variants

The macOS autofill extension can be built for different targets:
# Standard macOS app
npm run build:macos-extension:mac

# Mac App Store
npm run build:macos-extension:mas

# Mac App Store Development
npm run build:macos-extension:masdev
Each runs ./desktop_native/autofill_provider/build.sh with the appropriate target parameter.

Cleaning Build Artifacts

npm run clean:dist
Removes the ./dist directory containing packaged builds.

Post-Install

After npm install, the app automatically rebuilds native modules:
npm run postinstall  # Runs electron-rebuild
This ensures native modules are compiled for the correct Electron version.

Testing Builds

Directory Output (No Packaging)

npm run pack:dir
Creates an unpacked build in ./dist without creating installers. Useful for testing.

Distribution Build

npm run dist:dir
Builds and creates unpacked directory (combines build + pack:dir).

Build docs developers (and LLMs) love