electron-auto-updater-setup
Configure electron-updater for Electron applications with advanced features including code signing verification, delta updates, staged rollouts, and multiple release channels. This skill creates a complete auto-update infrastructure.
Capabilities
- Configure electron-updater with multiple providers (GitHub, S3, Generic, Spaces)
- Set up staged rollouts with percentage-based distribution
- Configure delta (differential) updates for efficient bandwidth usage
- Implement multiple release channels (stable, beta, alpha)
- Set up code signing verification for update packages
- Create update notification UI components
- Configure silent updates vs. interactive updates
- Implement rollback mechanisms
Input Schema
{
"type": "object",
"properties": {
"projectPath": {
"type": "string",
"description": "Path to the Electron project root"
},
"provider": {
"type": "object",
"properties": {
"type": { "enum": ["github", "s3", "generic", "spaces", "keygen"] },
"config": {
"type": "object",
"description": "Provider-specific configuration"
}
},
"required": ["type"]
},
"channels": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"default": { "type": "boolean" },
"allowDowngrade": { "type": "boolean" }
}
},
"default": [{ "name": "latest", "default": true }]
},
"features": {
"type": "object",
"properties": {
"deltaUpdates": { "type": "boolean", "default": true },
"stagedRollout": { "type": "boolean", "default": false },
"silentUpdate": { "type": "boolean", "default": false },
"autoInstallOnQuit": { "type": "boolean", "default": true },
"forceDevUpdateConfig": { "type": "boolean", "default": false }
}
},
"stagedRollout": {
"type": "object",
"properties": {
"enabled": { "type": "boolean" },
"initialPercentage": { "type": "number", "default": 10 },
"incrementStep": { "type": "number", "default": 20 },
"incrementInterval": { "type": "string", "default": "24h" }
}
},
"ui": {
"type": "object",
"properties": {
"generateComponents": { "type": "boolean", "default": true },
"framework": { "enum": ["react", "vue", "svelte", "vanilla"] },
"notifications": { "type": "boolean", "default": true }
}
}
},
"required": ["projectPath", "provider"]
}
Output Schema
{
"type": "object",
"properties": {
"success": { "type": "boolean" },
"files": {
"type": "array",
"items": {
"type": "object",
"properties": {
"path": { "type": "string" },
"type": { "enum": ["config", "main", "ui", "ipc", "utils"] }
}
}
},
"electronBuilderConfig": {
"type": "object",
"description": "electron-builder publish configuration to merge"
},
"envVariables": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"description": { "type": "string" },
"required": { "type": "boolean" }
}
}
},
"testCommands": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["success", "files"]
}
Generated File Structure
src/
main/
updater/
auto-updater.ts # Main updater logic
update-channels.ts # Channel management
staged-rollout.ts # Staged rollout logic
delta-updates.ts # Delta update handling
preload/
updater-api.ts # Exposed updater API
renderer/
components/
UpdateNotification/ # UI components
UpdateNotification.tsx
UpdateProgress.tsx
ReleaseNotes.tsx
shared/
update-types.ts # TypeScript types
Code Templates
Main Auto-Updater Module
import { autoUpdater, UpdateInfo } from 'electron-updater';
import { app, BrowserWindow, ipcMain } from 'electron';
import log from 'electron-log';
// Configure logging
autoUpdater.logger = log;
autoUpdater.logger.transports.file.level = 'info';
// Disable auto download - we control the flow
autoUpdater.autoDownload = false;
autoUpdater.autoInstallOnAppQuit = true;
export class AppUpdater {
private mainWindow: BrowserWindow | null = null;
constructor(mainWindow: BrowserWindow) {
this.mainWindow = mainWindow;
this.setupEventHandlers();
this.setupIpcHandlers();
}
private setupEventHandlers() {
autoUpdater.on('checking-for-update', () => {
this.sendToRenderer('update-status', { status: 'checking' });
});
autoUpdater.on('update-available', (info: UpdateInfo) => {
this.sendToRenderer('update-status', {
status: 'available',
version: info.version,
releaseNotes: info.releaseNotes,
releaseDate: info.releaseDate,
});
});
autoUpdater.on('update-not-available', () => {
this.sendToRenderer('update-status', { status: 'not-available' });
});
autoUpdater.on('download-progress', (progress) => {
this.sendToRenderer('update-progress', {
percent: progress.percent,
bytesPerSecond: progress.bytesPerSecond,
transferred: progress.transferred,
total: progress.total,
});
});
autoUpdater.on('update-downloaded', (info: UpdateInfo) => {
this.sendToRenderer('update-status', {
status: 'downloaded',
version: info.version,
});
});
autoUpdater.on('error', (error) => {
this.sendToRenderer('update-status', {
status: 'error',
error: error.message,
});
});
}
private setupIpcHandlers() {
ipcMain.handle('updater:check', async () => {
return autoUpdater.checkForUpdates();
});
ipcMain.handle('updater:download', async () => {
return autoUpdater.downloadUpdate();
});
ipcMain.handle('updater:install', () => {
autoUpdater.quitAndInstall(false, true);
});
ipcMain.handle('updater:set-channel', async (_, channel: string) => {
autoUpdater.channel = channel;
return autoUpdater.checkForUpdates();
});
}
private sendToRenderer(channel: string, data: unknown) {
this.mainWindow?.webContents.send(channel, data);
}
async checkForUpdates() {
return autoUpdater.checkForUpdates();
}
}
Staged Rollout Implementation
import { machineIdSync } from 'node-machine-id';
import crypto from 'crypto';
export class StagedRollout {
private machineId: string;
private rolloutPercentage: number;
constructor() {
this.machineId = machineIdSync();
this.rolloutPercentage = 100; // Full rollout by default
}
/**
* Deterministically decide if this machine should receive the update
* based on a hash of the machine ID
*/
shouldReceiveUpdate(version: string, rolloutPercentage: number): boolean {
const hash = crypto
.createHash('sha256')
.update(`${this.machineId}:${version}`)
.digest('hex');
// Convert first 8 hex chars to number (0 to 4294967295)
const hashNumber = parseInt(hash.substring(0, 8), 16);
// Normalize to 0-100
const bucket = (hashNumber / 0xffffffff) * 100;
return bucket < rolloutPercentage;
}
async fetchRolloutConfig(updateServerUrl: string, version: string) {
try {
const response = await fetch(
`${updateServerUrl}/rollout/${version}`
);
const config = await response.json();
return config.percentage || 100;
} catch {
return 100; // Default to full rollout on error
}
}
}
Multi-Channel Support
import { autoUpdater } from 'electron-updater';
import Store from 'electron-store';
const store = new Store();
export const UPDATE