Unsigned apps work. They just look dangerous.
What signing actually buys you
| Unsigned | Signed | |
|---|---|---|
| Windows | SmartScreen shows a blue "unrecognised app" warning; the user has to click "More info" then "Run anyway" | Installs normally |
| macOS | Gatekeeper refuses to open it; the user has to right-click and choose Open, or visit System Settings | Opens normally |
For a paid product, the warning costs you sales from exactly the cautious buyers you want. For an internal tool or a beta with people who know you, unsigned is fine.
Windows
You need an Authenticode certificate from a certificate authority such as SSL.com or DigiCert. Around $200 a year. Organisation Validation certificates take a few days; Extended Validation ones start clean with SmartScreen but cost more and usually ship on a hardware token.
Set two environment variables and build:
$env:CSC_LINK = "C:\path\to\cert.pfx"
$env:CSC_KEY_PASSWORD = "your-cert-password"
npm run build:winThe signing step is already in the build. It runs when those variables are present and skips silently when they are not, which is why unsigned local builds just work.
macOS
You need an Apple Developer account, $99 a year, and a Developer ID Application certificate. Signing alone is not enough on modern macOS: the app must also be notarized, which means Apple scans it and issues a ticket.
export CSC_LINK=/path/to/cert.p12
export CSC_KEY_PASSWORD=your-cert-password
export APPLE_API_KEY=/path/to/AuthKey_XXXX.p8
export APPLE_API_KEY_ID=XXXXXXXXXX
export APPLE_API_ISSUER=your-issuer-uuid
npm run build:macNotarization is a round trip to Apple and adds a few minutes to the build. It fails on things like a missing entitlement or an unsigned nested binary, and the error messages are specific enough to act on.
Linux
No signing. AppImage and .deb install without ceremony.
Doing this in CI
Never commit a certificate. Store the base64-encoded file and its password as encrypted repository secrets and expose them as the same environment variables. The GitHub Actions workflow in .github/workflows/ is already shaped for this.
docs/signing.md in the repo has the full walkthrough, including the entitlements file and the notarization failures worth recognising.
Next: Auto-Update.