update-electron-app gives an Electron app auto-updates in two lines
🌲 A drop-in module that adds autoUpdating capabilities to Electron apps
At a glance
- What is it?
- update-electron-app is a small TypeScript module from the Electron organisation that adds auto-updating to a desktop app, either through the free update.electronjs.org service or from your own static file storage, with the update lifecycle, the background download and the restart prompt handled for you. Its hard requirement is packaging: on Windows the Squirrel.Windows assets have to be attached to every release, or updates fail in silence.
- Who is it for?
- Adopt update-electron-app when you ship a macOS or Windows Electron app that needs to update itself, and you want either the public update service or your own bucket without writing the update lifecycle yourself. Do not adopt it if you cannot code sign your macOS builds, because that is a stated requirement, and check the Windows packaging rules before you promise updates to users.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Two calls in the main process
update-electron-app is described as a drop-in module that adds autoUpdating capabilities to Electron apps, and the whole integration is short.
const { updateElectronApp } = require('update-electron-app')
updateElectronApp()By default your repository URL is found in your app's package.json file, so in the simplest case there is nothing to configure. You can also pass options, for example to point at a specific repository, set a check interval and attach a logger:
const { updateElectronApp, UpdateSourceType } = require('update-electron-app')
updateElectronApp({
updateSource: {
type: UpdateSourceType.ElectronPublicUpdateService,
repo: 'github-user/repo'
},
updateInterval: '1 hour',
logger: require('electron-log')
})What the module does afterwards is spelled out in the README. Your app checks for updates at startup, then every ten minutes, and that interval is configurable. You do not need to wait for your app's ready event, because the module figures that out. If an update is found it is downloaded in the background, and when the download finishes a dialog is displayed letting the user restart the app now or later.
That last behaviour is the one product decision in the library. The download happens without asking, and the prompt comes after it, so a user is never blocked by an update dialog at an awkward moment, and the update is already on disk when they are asked.
The package is MIT licensed and published on npm as update-electron-app, with the release history at v3.1.2 in December 2025, v3.2.0 in May 2026 and v3.3.0 in June 2026, and the last push to the main branch on 2026-10-22.
Two update sources, and the public service does the fetching
The module supports two sources for the update payload, and the choice is made with the updateSource option.
The first is the free and open source update.electronjs.org service, selected with UpdateSourceType.ElectronPublicUpdateService. The second is static file storage, selected with UpdateSourceType.StaticStorage, where you point the module at a bucket path that already encodes the platform and the architecture:
const { updateElectronApp, UpdateSourceType } = require('update-electron-app')
updateElectronApp({
updateSource: {
type: UpdateSourceType.StaticStorage,
baseUrl: `https://my-bucket.s3.amazonaws.com/my-app-updates/${process.platform}/${process.arch}`
}
})The baseUrl pattern is the contract, and it is the same one the manual upload instructions describe. The file structure is `**/{platform}/{arch}/{artifact}`, so the files that need to exist include `**/win32/x64/RELEASES`, `**/darwin/arm64/RELEASES.json` and `**/darwin/arm64/My App v1.0.0.zip`.
If you use the public service, the README is clear that the server at update.electronjs.org handles the release fetching logic. Only releases that have valid SemVer tags and are not marked as draft or pre-release will be collected, and the latest release returned by the GitHub API for the repository that contains all the requisite binaries becomes the update target.
That draft and pre-release filter is a practical detail worth knowing about, because it is the sort of thing that produces a release that exists and is never offered to anybody.
The packaging rules decide whether updates work at all
The FAQ section of the README is where the real requirements live, and the first entry is about assets you have to build.
For macOS you need a .zip file, packaged with electron-forge or electron-installer-zip. For Windows you need .exe and .nupkg files, built with electron-forge or electron-winstaller.
On top of that, the README states that for Windows auto-updates to work, every GitHub Release must have the Squirrel.Windows assets attached, otherwise the update will silently fail. The list is: RELEASES, the manifest that Squirrel reads to discover available updates, the *-full.nupkg full update package, the *.exe installer, and optionally the *-delta.nupkg smaller delta packages used to speed up updates when present.
The requirements list at the top of the README adds the constraints. Your app has to run on macOS or Windows, your builds have to be code signed, and the code signing requirement is marked as macOS only. If you use update.electronjs.org, your app needs a public GitHub repository and the builds have to be published to GitHub Releases. If you use static file storage, the builds go to S3 or a similar static file host, using a tool like @electron-forge/publisher-s3.
So the module is the easy part of an auto-update setup. The hard part is producing artefacts that the platform updater will accept, and a release pipeline that attaches the right files to every release. A team that gets that wrong will see an app that never updates and no error to explain why.
The Windows double launch and the Squirrel startup events
One FAQ entry explains a symptom that is easy to misdiagnose. If your app is launching multiple times, the README says that on Windows extra launches indicate your app is not handling the Squirrel.Windows startup events, such as install, update and uninstall, that fire during these operations. The recommended fix is the electron-squirrel-startup module, which handles those events and avoids the unwanted launches.
The mechanism is worth understanding. Squirrel.Windows applies an update by launching the new version of the application, and the old process receives the shutdown and update events. If the application ignores them, the new instance starts while the old one is still running, and the user sees a second window appear. Handling the events is what lets the old process exit cleanly.
A second FAQ entry answers a question people are often unsure about: can this module be used by uploading a private app's builds to a public GitHub repository? The answer in the README is yes, with a smiley, which is the whole answer.
The release state question has a similar shape. If you are using the public update service, the server at update.electronjs.org handles the release fetching logic, and only releases with valid SemVer tags that are not draft or pre-release are collected. That filtering happens on the service side, not in your application, so a release you have marked as a pre-release while you test it will simply not be offered to anyone, which is the behaviour you want but not the behaviour you get by default from every release system.
Options, the return value and the five minute floor
The API section documents the options that are not part of the update source configuration.
updateInterval is a string, how frequently to check for updates, defaulting to 10 minutes, with a minimum allowed interval of 5 minutes, expressed as a human readable interval supported by the ms module. That is why the example in the usage section passes '1 hour'.
logger is an optional object that defines a log function, defaulting to console, and the README points at electron-log, a module that aggregates logs from the main and renderer processes into a single file.
notifyUser is an optional boolean that defaults to true, and when it is enabled the user is prompted to apply the update immediately after the download. Setting it to false leaves the update on disk and the application to be updated on its next launch.
The return value is the part with the most interesting contract. updateElectronApp returns an object with a stopUpdates function that stops the periodic update checks:
const { updateElectronApp } = require('update-electron-app')
const { stopUpdates } = updateElectronApp()
// Later, when you no longer want to check for updates:
stopUpdates()The README says stopUpdates is safe to call at any time, including before the app is ready or on platforms where updates are not supported, and that calling it more than once has no additional effect. Those two sentences remove the usual race conditions around a start and stop API, which is exactly the kind of detail that only gets written down when someone has been bitten by it.
A small module, a current toolchain, and a fast release line
The repository is small in the way a focused utility should be. There is a src directory, a test directory, jest.config.js, tsconfig.json, a yarn.lock and a.yarn directory with a.yarnrc.yml, so the package uses Yarn 4.10.3. The scripts are build with tsc, lint with oxlint and oxfmt in check mode, prepack which runs the build, test with jest, and a watch mode that runs jest with coverage. Husky handles the git hooks, and a.releaserc.json is present for the release configuration.
The interesting detail in the manifest is the version field, which reads 0.0.0-development, and the files array, which ships dist, src, the LICENSE and the README. The development version is replaced by the release tooling, so the number you install from npm is not the number in the repository. The published dependency list is two packages: github-url-to-object, which is what turns a repository URL into the owner and name the update service needs, and ms, which parses the human readable interval strings.
The release cadence is fast, with three releases in the last ten months across the 3.x line, and the last push to the main branch was on 2026-10-22, well after the most recent release.
For a module this small, that cadence is the point. The hard part of auto-updating is not the download, it is the packaging and the release pipeline, and a module that keeps moving is more likely to keep pace with the Electron release cycle than one that does not.
Editorial conclusion
Adopt update-electron-app when you ship a macOS or Windows Electron app that needs to update itself, and you want either the public update service or your own bucket without writing the update lifecycle yourself. Do not adopt it if you cannot code sign your macOS builds, because that is a stated requirement, and check the Windows packaging rules before you promise updates to users. Before you ship, verify the release artefacts with a real update cycle, since the README is explicit that a Windows release missing the Squirrel.Windows assets will silently fail, and read the minimum update interval, which is five minutes, against how often your users should be pulled forward to a new build.
Frequently asked questions
How do I add auto-updates to an Electron app?
Install the module with npm i update-electron-app and call updateElectronApp() in your main process. It finds the repository from your package.json, checks at startup and then every ten minutes, downloads in the background and shows a dialog when the download finishes.
Can update-electron-app serve updates from my own S3 bucket?
Yes, with updateSource type UpdateSourceType.StaticStorage and a baseUrl that points at your bucket path per platform and architecture. The files must follow the platform, arch and artifact path structure, for example a win32/x64/RELEASES file and a darwin/arm64/RELEASES.json file.
Why do my Windows updates fail without any error?
Because Squirrel.Windows needs specific assets attached to every GitHub Release, and the README says the update will silently fail without them: the RELEASES manifest, the *-full.nupkg package and the .exe installer, with *-delta.nupkg optional. On macOS you need a .zip built with electron-forge or electron-installer-zip, and your builds must be code signed.
Why does my Electron app launch several times after an update on Windows?
Extra launches mean the app is not handling the Squirrel.Windows startup events for install, update and uninstall. The README points at the electron-squirrel-startup module, which handles those events and avoids the unwanted launches.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/electron-update-electron-app)Was this useful?