Eric Guo's blog.cloud-mes.com

Hoping writing JS, Ruby & Rails and Go article, but fallback to DevOps note

Build X86 Electron on Arm64 Mac

Permalink

When building a Windows Electron app on Apple Silicon macOS, electron-builder --win defaults to the host architecture — so running:

cd packages/desktop && bun run package:win

produces arm64 Windows binaries instead of the expected x64.

The Fix

Force x64 explicitly with the --x64 flag when invoking the package command:

cd /path/to/packages/desktop
bun run build
bun run package:win -- --x64 --publish never

Or call electron-builder directly:

npx electron-builder --win --x64 --publish never --config electron-builder.config.ts

This produces the standard NSIS x64 artifacts:

dist/SigmaAgents-win-x64-<version>.exe
dist/SigmaAgents-win-x64-<version>.exe.blockmap
dist/latest.yml

To pin a specific version (e.g. 1.14.42), set the OPENCODE_VERSION env var before the build:

OPENCODE_VERSION=1.14.42 bun ./scripts/prepare.ts
bun run build
bun run package:win -- --x64 --publish never

Follow-up: Native Module Mismatch

After building with --x64, the .exe may launch but crash with:

Error: Cannot find module './windowsTerminal'

Root cause: bun run build resolves native modules (e.g. @lydell/node-pty) based on the host platform and architecture — darwin-arm64 — rather than the target win32-x64. The bundle ends up importing the macOS native binding, which fails when the Windows .exe tries to load it at runtime.

The Fix

Set RUST_TARGET=x86_64-pc-windows-msvc so the build step selects the correct native bindings for the target platform:

cd /path/to/packages/desktop
RUST_TARGET=x86_64-pc-windows-msvc bun run build
RUST_TARGET=x86_64-pc-windows-msvc bun run package:win -- --x64 --publish never

Verify

After the build, confirm the main bundle imports the correct platform binding:

rg "node-pty" out/main/index.js
# should show: @lydell/node-pty-win32-x64

And check the packaged app.asar includes the right native module:

npx asar list dist/win-unpacked/resources/app.asar | rg "windowsTerminal"
# should exist under: node_modules/@lydell/node-pty-win32-x64/lib/

TL;DR for cross-building on macOS

Both env vars are needed together for a working Windows build:

RUST_TARGET=x86_64-pc-windows-msvc \
bun run build && \
bun run package:win -- --x64 --publish never

Without RUST_TARGET, you get a working .exe installer but a broken main process that can't find its native modules.

Caveat: Code Signing

The .exe built on macOS will not be Windows-code-signed. Electron-builder's signing routines typically gate on process.platform === "win32" (and often GITHUB_ACTIONS === "true"), so they intentionally skip signing on macOS. If you need a signed Windows release artifact, you must either build and sign on a Windows machine or add a macOS-compatible signing path to your config.

Comments