Deploy renderer updates to Electron apps safely. Use full app updates only when the shell changes.
electron-ota is an open-source over-the-air update system for Electron renderer bundles — think Expo Updates, but for Electron. Ship UI fixes in minutes through a signed, health-checked, auto-rolling-back OTA channel, and fall back to full binary updates (via your existing electron-updater setup) only when the Electron shell itself changes.
Status: early release, under active development. The protocol and APIs are not stable yet, but the packages are published to npm under the @electron-ota scope: @electron-ota/cli, @electron-ota/electron, @electron-ota/core, and @electron-ota/server-contract. You can also run everything from this repo, which is how you test the whole system locally.
Getting started — from zero to your first rollback takes you from an empty directory to a working Electron app that updates itself over the air, survives a deliberately broken release, and rolls a channel back — entirely on your machine in ~20 minutes: no npm publishing, no cloud account, no certificates.
git clone <this-repo> electron-ota && cd electron-ota
pnpm install && pnpm build
# …then follow docs/guides/getting-started.mdYou'll build the app by hand (4 small files), then:
electron-ota init # config + Ed25519 signing keypair
electron-ota update --channel production # sign + publish a renderer OTA
electron-ota rollback production # undo a bad deploy, fleet-widePrefer a ready-made app? The electron-vite example is the same walkthrough with a real Vite renderer. Packaging integrations live in examples/electron-builder and examples/electron-forge; monorepo layout in examples/nx-monorepo.
- Your renderer ships as a signed, immutable zip; the shell
(main/preload/native) ships through normal installers. An opaque
runtimeVersionstring names the contract between them, and the SDK refuses any OTA built for a different runtime — that's the safety boundary. - The app loads its UI through
app://bundle/…, which points at the active bundle inuserData. Updates stage next to the current bundle and activate on restart via an atomic pointer swap — nothing is ever overwritten. - A staged update boots in probation: it must call
markHealthy()or it is retried, then automatically rolled back and blacklisted. A broken release costs each device at most two failed launches, then it heals itself. - Hosting is a static file tree (any web server or CDN), or the included self-hostable cloud server when you want percentage rollouts, adoption metrics, and the dashboard's rollback button. Same wire protocol either way; the server can never sign code.
| Package | Description |
|---|---|
@electron-ota/core |
Pure protocol logic: manifest schemas, JCS canonicalization, Ed25519 signing, compatibility gate, update state machine, rollout bucketing |
@electron-ota/electron |
Electron main-process SDK: check, download, verify, stage, activate, health check, automatic rollback |
electron-ota |
CLI: init, keys, update, promote, rollout, rollback, channel, status, release-binary |
@electron-ota/server-contract |
Shared API types and schemas for the device and management planes |
cloud-api |
Self-hostable update server: rollouts, adoption metrics, immutable deployment history |
dashboard |
Release-operations UI (served by cloud-api): rollout slider, failure rates, rollback button |
- Getting started tutorial — zero to first rollback, all local
- The runtimeVersion guide — the one concept that keeps OTA safe
- Security model — what signing does and doesn't protect
- Self-hosting guide — static files or one container
- Binary updates + electron-updater adapter — incl. the Mac App Store caveat
- SDK usage + safety model
- Protocol specification
- Design document · Implementation plan
pnpm install
pnpm build
pnpm test # 181 unit/integration tests
pnpm --filter @electron-ota/e2e test:e2e # 19 Electron + browser scenariosTest the packages as a consumer without publishing to npmjs — a local registry with npmjs proxying:
pnpm registry:local # Verdaccio on http://localhost:4873
pnpm publish:local # publish @electron-ota/* to it
# in any app on your machine:
npm install --registry http://localhost:4873 @electron-ota/electron @electron-ota/cli