electron-builder
Quick Start
Install:
bash
pnpm add electron-builder -D
pnpm add electron-updater # If using auto-updates
yaml
appId: com.example.myapp
productName: My App
files:
- "out/**/*"
- "package.json"
mac:
target: dmg
category: public.app-category.developer-tools
win:
target: nsis
linux:
target:
- AppImage
- deb
publish:
provider: github
json
{
"scripts": {
"build:mac": "electron-builder --mac",
"build:win": "electron-builder --win",
"build:linux": "electron-builder --linux",
"build:all": "electron-builder -mwl",
"release": "electron-builder --publish always"
}
}
CLI Reference
bash
electron-builder # Build for current platform
electron-builder -mwl # Build for all platforms
electron-builder --mac dmg # macOS DMG only
electron-builder --win nsis:ia32 # Windows NSIS 32-bit
electron-builder --linux deb tar.xz
electron-builder --dir # Unpacked dir (test builds)
electron-builder -p always # Build and publish
# Architecture flags
--x64 --ia32 --armv7l --arm64 --universal
# CLI config overrides
-c.extraMetadata.foo=bar
-c.mac.identity=null
-c.nsis.unicode=false
# Publish existing artifacts
electron-builder publish -f dist/*.exe -c electron-builder.yml
Publish flag values:
|
|
|
Configuration
Config locations (checked in order):
- > key
- (default, recommended)
- / /
electron-builder.config.js
/
- CLI:
Do NOT name JS config — conflicts with package name.
For full configuration options, file patterns, macros, icons, and directory settings:
See references/configuration.md
Essential Config Properties
| Property | Default | Description |
|---|
| | Do not change once deployed. Used as bundle ID (macOS) and AUMID (Windows). |
| package.json name | Display name (allows spaces) |
| | for fast test builds, for release |
| | Pack source into asar archive |
| auto | Glob patterns for app source files |
| — | Files copied outside asar (e.g. native addons) |
| — | Files copied to resources directory |
| | Fail build if not signed |
File Macros
Available in
, file patterns, and publish URLs:
,
,
,
,
,
,
,
,
Default Targets
| Platform | Default |
|---|
| macOS | DMG + ZIP |
| Windows | NSIS |
| Linux (cross) | Snap + AppImage (x64) |
| Linux (native) | Snap + AppImage (current arch) |
Code Signing
Signing is automatic when configured. Core environment variables:
| Env | Description |
|---|
| Certificate path/URL/base64 (.p12/.pfx) |
| Certificate password |
CSC_IDENTITY_AUTO_DISCOVERY
| / (macOS keychain auto-discovery) |
| Windows cert (when cross-signing from macOS) |
| Windows cert password |
macOS: Disable signing
bash
export CSC_IDENTITY_AUTO_DISCOVERY=false
# Or in config: mac.identity: null
# For ad-hoc (ARM): mac.identity: "-"
macOS: Notarization
yaml
mac:
hardenedRuntime: true
notarize: true # or { teamId: "TEAM_ID" }
Requires
,
APPLE_APP_SPECIFIC_PASSWORD
,
env vars.
Windows: Azure Trusted Signing
yaml
win:
azureSignOptions:
publisherName: "CN=Your Company"
endpoint: "https://eus.codesigning.azure.net"
certificateProfileName: "your-profile"
codeSigningAccountName: "your-account"
For complete code signing reference (CI setup, certificates, EV certs, cross-platform):
See references/code-signing.md
Auto Update (electron-updater)
Minimal setup
typescript
// main process
import electronUpdater, { type AppUpdater } from "electron-updater";
export function getAutoUpdater(): AppUpdater {
const { autoUpdater } = electronUpdater;
return autoUpdater;
}
const autoUpdater = getAutoUpdater();
autoUpdater.checkForUpdatesAndNotify();
Do NOT call —
is auto-generated at build time.
ESM Import (required workaround)
typescript
// CORRECT
import electronUpdater from "electron-updater";
const { autoUpdater } = electronUpdater;
// WRONG (may fail with ESM)
import { autoUpdater } from "electron-updater";
Auto-updatable targets
- macOS: DMG
- Windows: NSIS
- Linux: AppImage, DEB, Pacman (beta), RPM
macOS apps MUST be signed for auto-update. Squirrel.Windows NOT supported.
Events
typescript
autoUpdater.on("error", (err) => {});
autoUpdater.on("checking-for-update", () => {});
autoUpdater.on("update-available", (info) => {});
autoUpdater.on("update-not-available", (info) => {});
autoUpdater.on("download-progress", (progress) => {
// .bytesPerSecond, .percent, .total, .transferred
});
autoUpdater.on("update-downloaded", (info) => {
autoUpdater.quitAndInstall();
});
Debugging
typescript
import log from "electron-log";
autoUpdater.logger = log;
autoUpdater.logger.transports.file.level = "info";
For staged rollouts, custom updater instances, private repos, dev testing:
See references/auto-update.md
Publishing
Quick GitHub Releases setup
yaml
publish:
provider: github
releaseType: draft
Set
env var (personal access token with
scope).
Quick S3 setup
yaml
publish:
provider: s3
bucket: my-bucket-name
Quick Generic Server setup
yaml
publish:
provider: generic
url: https://example.com/releases
Upload artifacts +
manually.
Publish CLI behavior
| Condition | Default behavior |
|---|
| CI detected | |
| CI + tag pushed | |
| npm script | |
Release Channels
Version determines channel:
=
,
=
For all publishers (Bitbucket, GitLab, Keygen, Snap Store, Spaces), workflows, and advanced config:
See references/publishing.md
Platform Target Configuration
macOS
yaml
mac:
category: public.app-category.developer-tools
hardenedRuntime: true
darkModeSupport: true
target: dmg
entitlements: build/entitlements.mac.plist
notarize: true
Windows (NSIS)
yaml
nsis:
oneClick: true # false for assisted installer
perMachine: false
allowToChangeInstallationDirectory: false
createDesktopShortcut: true
deleteAppDataOnUninstall: false
include: build/installer.nsh # Custom NSIS script
differentialPackage: true
Linux
yaml
linux:
category: Development
desktop:
MimeType: "x-scheme-handler/myapp"
target:
- AppImage
- deb
- snap
For all target options (DMG, PKG, MAS, MSI, AppX, Snap, Flatpak, portable, custom NSIS scripts):
See references/platform-targets.md
Build Hooks
Execution order:
beforeBuild → beforePack → afterExtract → afterPack → [signing] →
afterSign → artifactBuildStarted → [build] → artifactBuildCompleted →
afterAllArtifactBuild
Inline (JS/TS config)
javascript
module.exports = {
afterSign: async (context) => {
if (context.electronPlatformName === "darwin") {
await notarize(context);
}
},
afterAllArtifactBuild: (result) => {
return ["/path/to/extra/file"]; // Additional files to publish
},
};
File reference (YAML config)
yaml
beforePack: "./scripts/before-pack.js"
afterSign: "./scripts/notarize.js"
javascript
// scripts/notarize.js
exports.default = async function(context) {
// context: { outDir, appOutDir, packager, electronPlatformName, arch, targets }
};
For all hooks, context interfaces, and programmatic API:
See references/hooks-and-programmatic.md
Common Patterns
Multi-platform CI build
yaml
# GitHub Actions pattern
mac:
target:
- target: dmg
arch: [x64, arm64]
win:
target:
- target: nsis
arch: [x64, ia32]
linux:
target:
- target: AppImage
arch: [x64, arm64]
- target: deb
arch: [x64, arm64]
publish:
provider: github
Complete config with auto-update and signing
yaml
appId: com.example.myapp
productName: My App
copyright: Copyright 2024 Example Inc.
asar: true
compression: normal
forceCodeSigning: true
directories:
output: dist
buildResources: build
files:
- "out/**/*"
- "package.json"
mac:
target: [dmg, zip]
hardenedRuntime: true
notarize: true
category: public.app-category.developer-tools
win:
target: nsis
nsis:
oneClick: false
perMachine: false
allowToChangeInstallationDirectory: true
linux:
target: [AppImage, deb]
category: Development
publish:
provider: github
electronUpdaterCompatibility: ">= 2.16"
Gotchas
- Never change after release — NSIS uses it for registry GUID
- macOS signing required for auto-update to work
- ESM import workaround needed for electron-updater in TypeScript
- Don't call — is auto-generated
- Squirrel.Windows not supported by electron-updater — use NSIS
- Windows env var limit 8192 chars — re-export cert without chain if too large
- conflicts with package name — use different filename
- Set
app.setAppUserModelId(appId)
in main process for Windows notifications