LogoPear Docs
How ToOperating an app

Build desktop distributables

Produce signed macOS, Windows, and Linux artifacts for a Pear Electron app, then assemble a multi-architecture deployment directory for pear stage.

This guide shows you how to produce per-OS distributables and assemble a deployment directory that pear stage can consume. It assumes you already ship with Electron tooling (for example Electron Forge) and a Pear release line; for the overall pipeline, read Release pipeline and Deploy your application.

Before you begin

  • Node.js and npm on each build host (or CI runners) for the target OS.
  • pear CLI available (npx pear) for later pear-build / pear stage steps.
  • Branding fields filled in package.json (name, productName, description, author, license) and icons under build/ where your template expects them.

Checklist (all platforms)

Complete these before you cut binaries you will ship to others:

  • Application metadata and icons are final for the brand you are releasing under.
  • You know which release line link (development, staging, rc, etc.) this build will track — see Release pipeline.
  • For macOS and Windows production paths, plan vendor signing up front (same certificate across builds for MSIX updates).

macOS

  1. On a Mac, run your project's macOS make script (often npm run make:darwin or electron-forge make --platform=darwin).

  2. Unsigned local .app bundles are fine for your machine; other Macs will quarantine unsigned builds. For OTA installs on other machines you need code signing and notarization with Apple credentials.

  3. Set the environment variables your template documents:

    MAC_CODESIGN_IDENTITY=identity APPLE_TEAM_ID=teamid APPLE_ID=id APPLE_PASSWORD=pw npm run make:darwin

    APPLE_PASSWORD is an app-specific password, not your Apple ID login password.

  4. Maintain build/entitlements.mac.plist for Hardened Runtime. Notarized apps require it; the defaults cover Bare native-addon compatibility:

    • cs.allow-jit — required for V8/Bare JIT compilation.
    • cs.allow-unsigned-executable-memory — required for the Bare runtime.

    Add or remove entitlements here as needed (com.apple.security.device.camera, com.apple.security.device.microphone, etc.). To load third-party native addons that dynamically link shared libraries built by a different developer, also add cs.disable-library-validation.

  5. If you are using pear ≤ v2.2.15, add a pear.stage.includes entry that keeps .github folders so notarization does not break on stripped resources:

    { "pear": { "stage": { "includes": [".github"] } } }

Follow the Electron Forge macOS code signing guide for credential setup.

Windows

  1. Install Windows SDK and PowerShell 7+ on the build host.

  2. Run your Windows make script (often npm run make:win32 or electron-forge make --platform=win32).

  3. Without signing credentials, @electron-forge/maker-msix generates a self-signed development certificate matching the Publisher field in build/AppxManifest.xml. The certificate is cached locally and reused across builds on the same machine, but is not portable — building on a different machine or clearing the cert store generates a new one.

  4. Edit build/AppxManifest.xml so Name, Publisher, DisplayName, and the executable path are correct for your brand. Several of these are declared in multiple locations.

  5. Install with Add-AppxPackage .\out\<AppName>-win32-x64\<AppName>.msix; uninstall with Get-AppxPackage -Name <AppName> | Remove-AppxPackage.

  6. For production MSIX, supply a persistent code signing certificate (WINDOWS_CERTIFICATE_FILE and WINDOWS_CERTIFICATE_PASSWORD):

    WINDOWS_CERTIFICATE_FILE=path/to/cert.pfx WINDOWS_CERTIFICATE_PASSWORD=password npm run make:win32

    Keep the Publisher field in AppxManifest.xml exactly equal to the certificate's CN — Windows rejects MSIX updates when the publisher string drifts, breaking OTA. Use the same certificate across every release for the lifetime of the install base.

See Microsoft's MSIX signing documentation.

Linux

  1. On Linux (or a Linux CI runner), run your Linux make script (often npm run make:linux).
  2. Verify the produced AppImage (or your chosen format) launches on a clean VM before you fold it into the deployment directory.

Build the deployment directory

After you have one build per target architecture (darwin arm64/x64, linux arm64/x64, win32 x64, etc.), run pear-build to merge them into a single deployment directory (typically package.json + by-arch/.../app).

  • Run pear-build outside the application source tree, or pass --target to a sibling folder — never nest the deployment folder inside a tree that will itself be staged, or sizes will balloon on every stage. See Troubleshoot desktop releases.

Example shape (paths illustrative only):

pear-build --package=./my-app/package.json \
  --darwin-arm64-app ./out/MyApp-darwin-arm64/MyApp.app \
  --darwin-x64-app ./out/MyApp-darwin-x64/MyApp.app \
  --linux-arm64-app ./out/MyApp-linux-arm64/MyApp.AppImage \
  --linux-x64-app ./out/MyApp-linux-x64/MyApp.AppImage \
  --win32-x64-app ./out/MyApp-win32-x64/MyApp.msix \
  --target my-app-1.2.3

Then continue with dry-run and real pear stage as described in Deploy your application.

Where to go next

On this page