name: electron-builder description: | Comprehensive guide for electron-builder (v26.x) packaging, code signing, auto-updates, and release workflows. Use when: (1) configuring electron-builder builds (electron-builder.yml or config.js/ts), (2) setting up macOS/Windows code signing or notarization, (3) implementing auto-updates with electron-updater, (4) publishing to GitHub Releases, S3, or generic servers, (5) configuring platform targets (NSIS, DMG, AppImage, Snap, PKG, MSI), (6) working with build hooks (beforePack, afterSign, afterAllArtifactBuild), or (7) using the programmatic API. Triggers on: electron-builder, electron-updater, code signing, notarize, NSIS, DMG, AppImage, auto-update, publish releases, build hooks, electron packaging, electron distribution.
electron-builder
Docs: https://www.electron.build (v26.8.x) Repo: https://github.com/electron-userland/electron-builder
Quick Start
Install:
pnpm add electron-builder -D
pnpm add electron-updater # If using auto-updates
Minimal config (electron-builder.yml):
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
Build scripts in package.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
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: onTag | onTagOrDraft | always | never
Configuration
Config locations (checked in order):
package.json>"build"keyelectron-builder.yml(default, recommended)electron-builder.json/.json5/.tomlelectron-builder.config.js/.ts- CLI:
--config <path>
Do NOT name JS config electron-builder.js — 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 |
|---|---|---|
appId |
com.electron.${name} |
Do not change once deployed. Used as bundle ID (macOS) and AUMID (Windows). |
productName |
package.json name | Display name (allows spaces) |
compression |
"normal" |
"store" for fast test builds, "maximum" for release |
asar |
true |
Pack source into asar archive |
files |
auto | Glob patterns for app source files |
extraFiles |
— | Files copied outside asar (e.g. native addons) |
extraResources |
— | Files copied to resources directory |
forceCodeSigning |
false |
Fail build if not signed |
File Macros
Available in artifactName, file patterns, and publish URLs:
${arch}, ${os}, ${platform}, ${name}, ${productName}, ${version}, ${channel}, ${ext}, ${env.VAR_NAME}
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 |
|---|---|
CSC_LINK |
Certificate path/URL/base64 (.p12/.pfx) |
CSC_KEY_PASSWORD |
Certificate password |
CSC_IDENTITY_AUTO_DISCOVERY |
true/false (macOS keychain auto-discovery) |
WIN_CSC_LINK |
Windows cert (when cross-signing from macOS) |
WIN_CSC_KEY_PASSWORD |
Windows cert password |
macOS: Disable signing
export CSC_IDENTITY_AUTO_DISCOVERY=false
# Or in config: mac.identity: null
# For ad-hoc (ARM): mac.identity: "-"
macOS: Notarization
mac:
hardenedRuntime: true
notarize: true # or { teamId: "TEAM_ID" }
Requires APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD, APPLE_TEAM_ID env vars.
Windows: Azure Trusted Signing
win:
azureSignOptions:
publisherName: "CN=Your Company"
endpoint: "https://eus.codesigning.azure.net"
certificateProfileName: "your-profile"
codeSigningAccountName: "your-account"
Requires AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET.
For complete code signing reference (CI setup, certificates, EV certs, cross-platform): See references/code-signing.md
Auto Update (electron-updater)
Minimal setup
// 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 setFeedURL() — app-update.yml is auto-generated at build time.
ESM Import (required workaround)
// 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
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
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
publish:
provider: github
releaseType: draft
Set GH_TOKEN env var (personal access token with repo scope).
Quick S3 setup
publish:
provider: s3
bucket: my-bucket-name
Set AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY.
Quick Generic Server setup
publish:
provider: generic
url: https://example.com/releases
Upload artifacts + latest.yml manually.
Publish CLI behavior
| Condition | Default behavior |
|---|---|
| CI detected | onTagOrDraft |
| CI + tag pushed | onTag |
npm script release |
always |
Release Channels
Version determines channel: 1.0.0 = latest, 1.0.0-beta.1 = beta
For all publishers (Bitbucket, GitLab, Keygen, Snap Store, Spaces), workflows, and advanced config: See references/publishing.md
Platform Target Configuration
macOS
mac:
category: public.app-category.developer-tools
hardenedRuntime: true
darkModeSupport: true
target: dmg
entitlements: build/entitlements.mac.plist
notarize: true
Windows (NSIS)
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
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)
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)
beforePack: "./scripts/before-pack.js"
afterSign: "./scripts/notarize.js"
// 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
# 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
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
appIdafter 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
setFeedURL()—app-update.ymlis 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
electron-builder.jsconflicts with package name — use different filename- Set
app.setAppUserModelId(appId)in main process for Windows notifications