Salta al contenuto principale

Auto Update per App Electron: Guida Pratica 2026

Distribuisci l'auto update per Electron senza fallimenti silenziosi. code reale, consigli sulla firma, guardrail per il rollout e strategie di rollback per team in produzione.

Auto Update per App Electron: Guida Pratica 2026

Hai rilasciato la build di Electron, la pagina di release è online e il primo ticket di supporto arriva prima ancora che il caffè sia pronto. Un utente dice che l'app non trova l'update. Un altro lo ha scaricato ma non riesce a installarlo. Un terzo sta ancora usando un vecchio binario con il flusso di autenticazione rotto, mentre i tuoi log non mostrano quasi nulla di utile.

Questa è la scomoda realtà dell' auto update per app Electron. L'updater API è solo un componente. Un rilascio in produzione dipende anche dalla firma della piattaforma, dalle policy di trasporto, dai manifest, dall'hosting, dagli eventi del ciclo di vita, dall'osservabilità, dai controlli di rollout e da un percorso di rollback. Se consideri uno qualsiasi di questi elementi come opzionale, una patch di routine può trasformarsi in un incidente improvviso.

Indice dei contenuti

L'incidente dell'aggiornamento alle 2:00 che ha dato vita a questa guida

Il rilascio aveva superato la CI e sembrava tutto normale. Tarda venerdì, uno sviluppatore ha pushato un build Electron non firmato, e il job di publish ha caricato abbastanza asset da far apparire il rilascio completo. L'app si avviava in testing, ma nessuno aveva testato il percorso di update da un build di produzione installato.

Alle 2:08, PagerDuty ha allertato l'ingegnere di turno. Un nuovo flusso di autenticazione è fallito per parte della flotta, e gli utenti che avevano ricevuto l'update non riuscivano a fare il login. Altri utenti sono rimasti sulla versione precedente perché l'updater non riusciva a verificare o installare l'artifact. Alcuni clienti avevano un rilascio corrotto, mentre il resto della flotta eseguiva una versione diversa senza una spiegazione chiara.

L'indagine ha seguito cinque passaggi:

  1. Controlla il feed del rilascio. Il binario esisteva, ma i metadati attesi non stabilivano chiaramente quali client dovessero riceverlo. Un manifest è un contratto tra la release pipeline e i client installati, non un dettaglio opzionale dell'upload.
  2. Ispeziona la firma. Il rilascio non era firmato correttamente, quindi la verifica è fallita sulle piattaforme colpite. La firma deve bloccare la pubblicazione se manca o è non valida.
  3. Confronta i log dei client. Gli errori di aggiornamento non raggiungevano mai la telemetria centrale. L'applicazione ignorava l'evento e continuava a girare, lasciando il team senza prove affidabili.
  4. Controlla i rollout controls. Non c'erano canali interni o cohort di staging. Ogni client idoneo utilizzava lo stesso feed, quindi il guasto si è propagato senza un punto di contenimento.
  5. Cerca un rollback. Il team non aveva procedure testate per ripubblicare la versione precedente o per allontanare i client dalla release corrotta.

La documentazione ufficiale di Electron chiarisce i limiti della piattaforma. Linux non ha il supporto nativo per l'auto-updater, e le richieste di aggiornamento su macOS devono soddisfare i requisiti di App Transport Security. La documentazione identifica inoltre la firma come prerequisito per aggiornamenti macOS affidabili e per la verifica della release. La documentazione di Electron autoUpdater definisce i vincoli di API, mentre il sistema di release deve imporre i controlli operativi circostanti.

Lezione postmortem: Un updater che non sa spiegare cosa è successo è solo un tentativo di installazione remota senza telemetria.

Il costo è andato oltre il tempo di engineering. I clienti hanno perso fiducia nel client desktop, il supporto ha dovuto spiegare comportamenti inconsistenti e il team ha passato il giorno lavorativo successivo a ricostruire un processo di release che avrebbe dovuto esistere prima dell'incidente.

Tratta l'auto-update come un sistema operativo. La firma è un gate di release, i manifest definiscono il contratto con il client, i rollout channel limitano l'esposizione e il rollback deve essere un percorso testato, non un'invenzione d'emergenza.

Scegliere il giusto percorso per l'updater di Electron

Alle 2 del mattino, una scelta errata dell'updater diventa un problema operativo. Un aggiornamento di un binario nativo deve gestire firma, manifest, installer e rollback. Un cambio di solo JavaScript o CSS nel renderer segue un percorso diverso. Contano anche i vincoli di hosting: un piccolo progetto ospitato su GitHub non richiede gli stessi controlli di release di un servizio di distribuzione enterprise.

Per i progetti che usano electron-builder con pubblicazione di artifact firmati, electron-updater è solitamente il default più pratico. Il suo ecosistema copre i target di pubblicazione, i manifest di release, il download degli artifact e l'installazione al prossimo avvio. Supporta diversi modelli di hosting, ma il tuo team resta responsabile di firma, disponibilità del feed, policy dei channel, controlli di rollout e monitoring. L'integrazione dell'updater di Integrazione dell'updater di Electron per Capgo è rilevante quando si valuta un modello di delivery ibrido per i bundle del web layer insieme ai Native Build.

update-electron-app si adatta a team che desiderano un'integrazione leggera con le GitHub Releases. Effettua un controllo all'avvio e poi a intervalli ricorrenti, mantenendo il setup semplice ma offrendo meno flessibilità per la selezione avanzata dei canali, il rollout graduale e le regole di rollback personalizzate. Il pacchetto è adeguato per un processo di rilascio ridotto, a patto che le GitHub Releases e la loro disponibilità soddisfino i tuoi requisiti operativi.

Opzione Controllo Hosting Supporto Signing Canali & Rollout Graduali Carico di Manutenzione
electron-updater S3, GitHub, HTTPS generico e altri target di pubblicazione Si integra con il signing del rilascio pacchettizzato Base solida, la policy personalizzata risiede solitamente nel feed Moderato
aggiornare un'app Electron Principalmente semplici workflow GitHub Releases Utilizza il modello di firma Electron sottostante Limitato, a meno di aggiungere servizi esterni Basso
Squirrel.Windows o Squirrel.Mac Flusso di distribuzione orientato alla piattaforma Dipende dai requisiti di firma della piattaforma Possibile, ma richiede infrastrutture di release extra Moderato per applicazioni legacy
Servizio custom Controllo totale su manifest, autorizzazioni, cohort e feed Tuo il design della verifica e la gestione delle chiavi Massima flessibilità Alto
Live Updates di Capgo Delivery gestita per i bundle del web layer Usa il suo modello di updater e delivery Targeting del pubblico e delivery basata sui canali Modello operativo separato dagli update del binario nativo

Un servizio custom come Hazel, Nuts o un feed interno è la scelta giusta quando autorizzazione al rilascio, targeting dei tenant, audit log o regole di deployment regolamentate giustificano il costo di implementazione. Il compromesso è la gestione continua: il tuo team deve definire la semantica del manifest, proteggere le chiavi di firma, preservare la compatibilità con i client e testare download falliti, rilasci rifiutati e comportamenti di rollback.

Con i Live Updates puoi distribuire modifiche solo al renderer senza ricostruire la shell nativa. Non sostituiscono gli update binari quando cambiano Electron, i moduli nativi, i permessi o il comportamento dell'installer. Usa electron-updater se non ti serve una logica di rollout custom. Se serve una logica custom, costruiscila seguendo le convenzioni consolidate di manifest e artifact, invece di ricreare da zero il comportamento di download e differential-update. La strada più affidabile è quella che il tuo team può osservare, mettere in staging e invertire sotto pressione.

Implementare il flusso di Auto-Update nel Main Process

Il main process deve gestire il controllo e l'installazione degli update. Il renderer può mostrare lo stato, ma non deve decidere se un update eseguibile è affidabile o quando l'app deve chiudersi.

Configura prima il target di pubblicazione

Una configurazione minima di electron-builder potrebbe essere questa:

{
  "build": {
    "appId": "com.example.desktop",
    "publish": [
      {
        "provider": "s3",
        "bucket": "example-electron-releases",
        "channel": "stable"
      }
    ],
    "nsis": {
      "oneClick": false,
      "allowToChangeInstallationDirectory": true
    }
  }
}

Mantieni separati i feed beta e stable. Un channel è una policy di rilascio, non un'etichetta nella UI. Ogni channel deve puntare all'artifact firmato e al manifest corretti.

Pianifica i controlli ed espone gli eventi del ciclo di vita

Chiamare checkForUpdates() solo all'avvio è un errore comune in produzione. Un utente può lasciare l'app aperta per giorni, quindi il main process necessita di un intervallo controllato e di una strategia di retry che gestisca l'operatività offline.

const { app, BrowserWindow, ipcMain } = require('electron');
const { autoUpdater } = require('electron-updater');

let mainWindow;
let isQuitting = false;
let retryDelay = 60 * 1000;

function sendUpdateStatus(status, payload = {}) {
  if (mainWindow && !mainWindow.isDestroyed()) {
    mainWindow.webContents.send('update-status', { status, ...payload });
  }
}

function scheduleUpdateCheck() {
  setTimeout(async () => {
    try {
      await autoUpdater.checkForUpdates();
      retryDelay = 60 * 1000;
    } catch (error) {
      sendUpdateStatus('error', { message: error.message });
      retryDelay = Math.min(retryDelay * 2, 30 * 60 * 1000);
    }
    scheduleUpdateCheck();
  }, retryDelay);
}

app.whenReady().then(() => {
  mainWindow = new BrowserWindow({
    webPreferences: {
      preload: require('path').join(__dirname, 'preload.js')
    }
  });

  autoUpdater.autoDownload = true;
  autoUpdater.autoInstallOnAppQuit = false;

  autoUpdater.on('checking-for-update', () => {
    sendUpdateStatus('checking');
  });

  autoUpdater.on('update-available', info => {
    sendUpdateStatus('available', { version: info.version });
  });

  autoUpdater.on('download-progress', progress => {
    sendUpdateStatus('progress', { percent: progress.percent });
  });

  autoUpdater.on('update-downloaded', info => {
    sendUpdateStatus('downloaded', { version: info.version });
  });

  autoUpdater.on('error', error => {
    sendUpdateStatus('error', { message: error.message });
  });

  autoUpdater.checkForUpdates().catch(error => {
    sendUpdateStatus('error', { message: error.message });
  });

  scheduleUpdateCheck();
});

ipcMain.handle('install-update', () => {
  isQuitting = true;
  autoUpdater.quitAndInstall(false, true);
});

app.on('before-quit', event => {
  if (!isQuitting) {
    return;
  }
});

Il comportamento esatto dell'evento di update varia per piattaforma e setup di packaging, quindi testa dagli artifact installati invece che in modalità sviluppo. Anche la documentazione di Electron segnala problemi di timing all'avvio su Windows, incluso il caso Squirrel al primo avvio. Non triggerare un controllo update prima che l'app abbia completato l'inizializzazione specifica della piattaforma.

Informa il renderer senza bloccare il lavoro

Il preload bridge dovrebbe esporre un API limitato:

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('updates', {
  onStatus(callback) {
    ipcRenderer.on('update-status', (_event, status) => callback(status));
  },
  install() {
    return ipcRenderer.invoke('install-update');
  }
});

Una barra di progresso lato renderer può rimanere volutamente semplice:

window.updates.onStatus(status => {
  const progress = document.querySelector('#update-progress');
  const message = document.querySelector('#update-message');

  if (status.status === 'progress') {
    progress.hidden = false;
    progress.value = status.percent;
    message.textContent = `Downloading update, ${Math.round(status.percent)}%`;
  }

  if (status.status === 'downloaded') {
    message.textContent = `Version ${status.version} is ready to install`;
  }

  if (status.status === 'error') {
    message.textContent = 'The update could not be downloaded. We will retry later.';
  }
});

Limita l'installazione al consenso dell'utente in produzione, a meno che la tua app non debba riavviarsi subito. Imposta un isQuitting flag prima quitAndInstall(), altrimenti i normali handler di chiusura finestra potrebbero impedire l'avvio dell'installer.

Screenshot da https://raw.githubusercontent.com/electron-userland/electron-builder/master/docs/electron-builder-autoupdate.png

Due fallimenti richiedono test espliciti. Primo, un client già in esecuzione deve chiamare checkForUpdates() a intervalli regolari, non solo all'avvio. Secondo, l'evento error deve arrivare ai log e alla telemetria. Se l'app lo ignora senza segnalarlo, il tuo workflow di troubleshooting si baserà su supposizioni invece che su prove concrete.

Configurare la CI/CD per Release Firmate e Manifest

La pipeline di release è l'unica fonte di verità per ciò che installano gli utenti. Un build locale che funziona sulla macchina di un dev non garantisce che il binario, il manifest, la firma e il channel pubblicati descrivano la stessa release.

Il modello di publish di electron-builder prevede che i metadati della release e l'update target viaggino insieme. In molte configurazioni, ciò significa un artifact come latest.yml per Windows e latest-mac.yml per macOS, insieme ai pacchetti specifici della piattaforma e ai file blockmap. Un manifest mancante può rendere invisibile ai client un binario perfettamente valido.

Rendi esplicita la firma nella CI

Un pattern semplificato per GitHub Actions è questo:

name: release

on:
  push:
    tags:
      - "v*"

jobs:
  build:
    strategy:
      matrix:
        os: [macos-latest, windows-latest]
    runs-on: ${{ matrix.os }}

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 24
          cache: npm

      - run: npm ci
      - run: npm run test
      - run: npm run build

      - name: Build and publish
        shell: bash
        env:
          CSC_LINK: ${{ secrets.CSC_LINK }}
          CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
          WIN_CSC_LINK: ${{ secrets.WIN_CSC_LINK }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        run: npx electron-builder --publish always

Usa secret specifici per piattaforma e tieni i materiali di firma fuori dal repository. Un errore di firma deve interrompere il job, non generare un fallback non firmato che qualcuno carichi manualmente.

Variabile Scopo
CSC_LINK Certificato macOS o riferimento al certificato
CSC_KEY_PASSWORD Password per il materiale di firma macOS
WIN_CSC_LINK Certificato Windows o riferimento al certificato
AWS_ACCESS_KEY_ID Credenziali di pubblicazione con accesso limitato
AWS_SECRET_ACCESS_KEY Secret associato alle credenziali di pubblicazione

La configurazione di pubblicazione deve identificare provider e channel in modo coerente:

{
  "build": {
    "publish": {
      "provider": "s3",
      "bucket": "example-electron-releases",
      "channel": "stable",
      "publishAutoUpdate": true,
      "updaterCacheDirName": "example-desktop-updater"
    }
  }
}

Prima della pubblicazione, blocca il job in base alla versione del pacchetto, al tag, al commit SHA e al risultato dello smoke-test. Dopo la pubblicazione, verifica che il feed contenga il manifest previsto e che il manifest punti all'artifact esatto generato da quel job. La continuous integration setup guide è utile quando si formalizzano questi controlli; anche i team che confrontano l'orchestrazione delle pipeline possono trarre vantaggio dal capire quando usare insieme Jenkins e Ansible.

I comandi che spesso causano un rilascio incompleto sono intenzionalmente banali:

npx electron-builder --publish never
test -f dist/latest.yml
test -f dist/latest-mac.yml
find dist -name "*.blockmap" -print

Questi controlli non sostituiscono un test di installazione firmata. Servono però a intercettare l'errore operativo di caricare un binario senza i metadati necessari ai client per scoprirlo.

Rollout, Channel e Strategia di Rollback

Un feed di rilascio dovrebbe comportarsi più come un target di deployment che come una cartella di download. Mantieni internal, beta, e ultima i canali sono separati, ognuno con il proprio manifest e set di artifact firmati. La promozione deve spostare una release testata tra le policy, non sovrascrivere un file durante il download dei client.

La separazione dei canali protegge anche la produzione dalle build di test accidentali. L'updater deve sapere se un client appartiene a una cohort interna, a un pubblico beta o alla popolazione stable prima di valutare il feed.

Usa le cohort prima del rilascio su larga scala

Un campo custom nel manifest può gestire il rilascio graduale:

version: 4.8.0
path: Example-Setup-4.8.0.exe
sha512: signed-artifact-hash
rolloutPercentage: 10

Il main process può assegnare un bucket stabile per utente, per poi confrontarlo con rolloutPercentage. L'assegnazione stabile è fondamentale. Un utente che passa tra stati elegibili e non elegibili a ogni controllo avrà un comportamento imprevedibile, rendendo difficili i report di supporto.

Espandi la cohort solo dopo che la release ha superato la finestra di osservazione. La finestra deve riflettere i tuoi pattern di utilizzo, ma la decisione deve basarsi su segnali, non solo sul calendario. Monitora i risultati degli update-check, il completamento dei download, la salute al lancio, i crash, le eccezioni del renderer e il successo dell'autenticazione.

Segnale Azione Motivo
Gli errori di feed o di firma superano la soglia approvata dal team Blocca il rollout I client potrebbero non riuscire a validare o trovare il rilascio
I controlli post-update al lancio falliscono Ripristina il feed Il binario potrebbe installarsi ma fallire all'avvio
Le eccezioni del renderer aumentano dopo la promozione Mantieni la cohort attuale L'installer nativo potrebbe essere integro mentre la nuova applicazione code no
I segnali rientrano nel budget del rilascio Espandi la cohort I dati supportano un'esposizione più ampia

Non confondere il rollback con l'eliminazione di un artifact. I client esistenti potrebbero avere metadati in cache e alcuni potrebbero già eseguire la versione errata. Un piano di rollback richiede un rilascio firmato precedente, un cambio del feed e un comportamento del client in grado di recuperare.

Regola operativa: Il rollback deve poter essere eseguito dall'ingegnere on-call senza dover ricostruire l'applicazione durante l'incidente.

In pratica, il runbook dovrebbe ripristinare il manifest della release precedente sul canale interessato, invalidare lo staging marker e confermare che i nuovi controlli puntino alla versione sicura. Se il problema riguarda il renderer code invece del native shell, un rollback mirato al web-layer potrebbe essere più veloce. Una piattaforma come i rollout graduali di Capgo può essere rilevante per quel layer di delivery separato, ma non deve oscurare il confine tra un rollback del binario nativo e uno del web-bundle.

Trattare l'Auto-Update come un controllo di sicurezza

Un updater di Electron scarica l'eseguibile code e può installarlo con pochissima interazione da parte dell'utente. Questo rende il percorso di aggiornamento un perimetro di sicurezza, non una semplice funzione di comodità. La documentazione ufficiale di Electron descrive vincoli di piattaforma come macOS ATS, e la sicurezza ha documentato uno scenario del 2022 in cui attaccanti che controllavano l'infrastruttura di update potevano distribuire pacchetti malevoli che superavano comunque i controlli di firma code, come discusso nella documentazione sulla sicurezza dell'auto-update di Electron Builder.

La firma di Code resta fondamentale, ma non è l'intero modello di fiducia. Firma ogni release, verifica il certificato e l'identità durante la CI e mantieni una procedura documentata per la rotazione delle chiavi. Su macOS, combina la firma con la notarizzazione e l'hardened runtime adatto alla tua app. Su Windows, rendi auditabili la proprietà del certificato, il rinnovo e l'accesso ai build. Linux richiede una strategia specifica per la distribuzione, poiché Electron non offre un updater universale integrato.

Proteggi i metadati con la stessa cura del binario

Un binario firmato può essere associato alla release sbagliata se il canale dei metadati è compromesso o configurato male. Valuta l'aggiunta di una firma del manifest verificata tramite una chiave pubblica integrata nell'app, imposta una versione minima consentita e rifiuta i downgrade inaspettati, a meno che un percorso di recovery autorizzato non lo permetta esplicitamente.

Anche il feed richiede controlli di produzione:

  • Limita l'accesso alla pubblicazione: Assegna alla CI solo i permessi necessari per pubblicare gli asset della release.
  • Proteggi i segreti di firma: Conserva certificati e chiavi private in uno storage di segreti gestito, non nei file del repository.
  • Blocca le dipendenze: Blocca Electron, electron-builder e le dipendenze transitive nella CI.
  • Revisiona gli artifact: Scansiona i pacchetti generati e confrontali con il commit e la versione previsti.
  • Richiedere un trasporto sicuro: Seguire i requisiti ATS e HTTPS rigorosi per le richieste di update.
  • Monitorare i fallimenti di verifica: Tratta i ripetuti errori di firma o del manifest come eventi di sicurezza, non come semplice rumore di rete.

L'ecosistema di tooling di Electron continua ad aggiungere supporto per packaging e updater, ma la manutenzione non elimina la necessità di un threat modeling. L'obiettivo pratico è garantire che un attaccante che compromette un bucket, una CDN o una fase di build non possa comunque far accettare un rilascio non autorizzato al client. La guida alla verifica della firma fornisce il contesto utile per progettare questo ulteriore livello di verifica.

Diagramma del processo di runbook per gli update in produzione in quattro step: verifica, rollout graduale, monitoraggio incidenti e protocolli di rollback.

Runbook e Checklist per l'Update in Produzione

Un rilascio è pronto solo quando un altro ingegnere può gestirlo sotto pressione. Tieni la checklist vicina al job di deployment e al canale degli incidenti.

Gate pre-rilascio

  • Identità della versione: Verifica che la versione del pacchetto, il tag di release, il commit SHA e il changelog coincidano.
  • Firma: Verifica che ogni artifact sia firmato e che la notarizzazione o la validazione equivalente sia completata.
  • Contratto del manifest: Verifica che latest.yml, latest-mac.yml, hash, percorsi e blockmap corrispondono agli artifact caricati.
  • Sicurezza del canale: Pubblica nel feed interno o beta prima di promuovere il canale di release.
  • Telemetria: Conferma che i controlli degli aggiornamenti, il download, l'installazione, l'avvio e gli errori vengano ricevuti correttamente.

Canary e rollout completo

  • Controllo dei cohort: Inizia con un pubblico beta o interno molto ristretto.
  • Budget di salute: Sospendi la promozione se fallimenti nel lancio, download degli update, eccezioni del renderer o errori di autenticazione superano i limiti approvati dal team.
  • Approvazione promozione: Richiedi una decisione esplicita (go/no-go) prima di spostare il rilascio nel feed stabile.
  • Impatto sui clienti: Prepara i messaggi di supporto prima della distribuzione su larga scala, non dopo il primo incidente.

Gestione degli incidenti

Se il nuovo binario non si avvia, il processo di spawning si interrompe o i download degli update falliscono, ferma subito la promozione. Ripristina il precedente manifest firmato, invalida il marker di staging e verifica che i nuovi client puntino alla versione precedente. Conferma tramite telemetria che il parco dispositivi si stia riprendendo prima di comunicare la chiusura dell'incidente.

I comandi esatti di rollback dipendono dal tuo provider, ma la sequenza deve sempre essere documentata: riporta il manifest del canale alla versione precedente, invalida il tag di staging, invia un marker di forced-update se necessario e verifica il percorso di downgrade con telemetria live. Un rollback non testato è solo una speranza.

Un'infografica professionale con checklist per gestire gli aggiornamenti del software in produzione, inclusi i passaggi di pianificazione, esecuzione e validazione post-aggiornamento.


Capgo offre un updater per Electron per distribuire modifiche firmate al web layer, canali mirati, controlli di rollout e osservabilità degli aggiornamenti, senza dover ricostruire il Native Build per ogni modifica al renderer. Se desideri separare il rilascio dei binari nativi dalla distribuzione controllata di JavaScript e CSS, visita Capgo ed effettua una valutazione insieme alla tua attuale pipeline di rilascio Electron.

Live update per le app Capacitor

Quando un bug del web layer è live, rilascia il fix tramite Capgo invece di aspettare giorni per l'approvazione degli store. Gli utenti ricevono l'update in background, mentre le modifiche native restano nel normale percorso di review.

Le ultime dal nostro blog

Capgo ti offre i migliori insight per creare un'app mobile davvero professionale.