Auto-Updates
Ship updates confidently. Auto-updates keep users on the latest version without manual downloads— critical for security patches and feature releases.
Desktop apps don't have the luxury of "just refresh the page." Users run old versions for months unless you make updates frictionless. Auto-updates solve this—your app checks for updates, downloads in the background, and installs on next launch.
How Auto-Updates Work
The update flow is straightforward: check for updates → download if available → install on restart. The complexity is in the details: differential updates, rollback handling, and user experience.
Check
Query update server
Download
Background download
Verify
Check signature
Install
On next restart
🎯 VibeBlaster Update Strategy
VibeBlaster checks for updates on launch and every 4 hours. Downloads happen silently in the background. When ready, users see a subtle notification: "Update available. Restart to install." No forced restarts, no interruptions.
For critical security patches, I use a more prominent banner—but still let users choose when to restart.
Setting Up electron-updater
electron-updater is the standard solution. It works with GitHub Releases, S3, or any static file server. Configuration lives in your package.json or electron-builder config.
Installation
npm install electron-updaterIncluded with electron-builder. Handles differential updates, code signing verification, and platform-specific installers.
Update Providers
- • GitHub Releases - Free, easy setup
- • S3/Spaces - More control, private
- • Generic server - Any static host
- • Private server - Full control
Configuration
Add publish configuration to your package.json. This tells electron-updater where to check for updates.
// package.json
{
"build": {
"appId": "com.yourcompany.yourapp",
"publish": {
"provider": "github",
"owner": "your-username",
"repo": "your-repo"
}
}
}Basic Implementation
The update logic lives in your main process. Listen for events and communicate with the renderer to show progress and prompt for restart.
import { autoUpdater } from 'electron-updater';
// Configure behavior
autoUpdater.autoDownload = false; // Let user choose
autoUpdater.autoInstallOnAppQuit = true;
// Check on launch (after 3 second delay)
app.whenReady().then(() => {
setTimeout(() => autoUpdater.checkForUpdates(), 3000);
});
// Handle events
autoUpdater.on('update-available', (info) => {
// Notify renderer: "Update v{info.version} available"
mainWindow.webContents.send('update-available', info);
});
autoUpdater.on('download-progress', (progress) => {
// Send progress to renderer for UI
mainWindow.webContents.send('download-progress', progress.percent);
});
autoUpdater.on('update-downloaded', () => {
// Notify renderer: "Ready to install"
mainWindow.webContents.send('update-ready');
});
// IPC handler for user-initiated install
ipcMain.on('install-update', () => {
autoUpdater.quitAndInstall();
});Update UX: Don't Be Annoying
The worst update experiences interrupt users mid-task. The best are invisible until the user is ready. Download silently, notify subtly, let users choose when to restart.
❌ Bad UX
- • Modal popup interrupting work
- • Forced restart without warning
- • "Update now or quit" ultimatums
- • Download blocking the UI
- • No progress indication
✅ Good UX
- • Subtle notification badge/banner
- • "Restart when you're ready"
- • Background download
- • Progress bar if user wants to see it
- • Release notes available
Update Notification Pattern
Show a non-intrusive banner when an update is ready. Include version number and what's new. Let users dismiss or install.
Version 2.1.0 is ready to install
New: Dark mode, performance improvements
⚠️ Security Updates Are Different
For critical security patches, be more insistent. Show a prominent warning explaining the risk. Consider blocking certain features until updated. But still don't force-restart—give users time to save their work.
Release Channels & Staged Rollouts
Don't ship updates to everyone at once. Use channels (stable, beta) and staged rollouts (10% → 50% → 100%) to catch issues before they affect all users.
🟢 Stable
Production releases. Thoroughly tested. Default for all users.
channel: 'latest'🔵 Beta
Pre-release features. Opt-in users help find bugs before stable.
channel: 'beta'🟣 Alpha
Internal testing. Unstable, may break. Developers only.
channel: 'alpha'Staged Rollout Strategy
Roll out to a percentage of users first. Monitor crash reports and feedback. If issues arise, pause the rollout before it affects everyone.
💡 Differential Updates
electron-updater supports differential updates—only downloading changed files instead of the full app. A 120MB app might have a 5-20MB update. Enable with differentialDownload: true. Faster downloads, happier users.
When Updates Go Wrong: Rollback
Sometimes updates break things. You need a plan for when that happens—monitoring to detect issues, and a way for users to recover.
Detect Issues
- • Crash reporting - Sentry, Bugsnag
- • Health checks - App starts successfully?
- • User feedback - Support tickets spike?
- • Metrics - Usage patterns change?
Recovery Options
- • Pause rollout - Stop new installs
- • Hotfix - Ship fix as new version
- • Manual rollback - Link to previous version
- • Auto-rollback - Detect crash loops, revert
⚠️ The Crash Loop Problem
If an update causes the app to crash on startup, users are stuck—they can't open the app to download a fix. Implement crash detection: if the app crashes 3 times in a row on startup, offer to reinstall the previous version or reset to defaults.
Auto-Update Best Practices
Updates Are Just the Beginning
You can now ship updates confidently—users get new features and security patches without lifting a finger. Combined with staged rollouts, you can iterate quickly while catching issues early.
Next up: Testing. Before you can ship updates confidently, you need to know they work. Let's build a testing strategy that catches bugs before users do.