Saltar al contenido principal

Auto update de apps Electron: guía práctica 2026

Lanza auto updates en Electron sin fallos silenciosos. code real, consejos de signing, guardrails de rollout y estrategias de rollback para equipos de producción.

Auto update de apps Electron: guía práctica 2026

Has lanzado el build de Electron, la página de release ya está publicada y el primer ticket de soporte llega antes de que la cafetera termine. Un usuario dice que la app nunca encontró la actualización. Otro la descargó pero no puede instalarla. Un tercero sigue usando un binario antiguo con un flujo de autenticación roto, mientras que tus logs no muestran casi nada útil.

Esa es la incómoda realidad de la actualización automática de apps Electron. El updater API es solo un componente. Un release en producción también depende de la firma de la plataforma, la política de transporte, los manifiestos, el hosting, los eventos de ciclo de vida, la observabilidad, los controles de rollout y una ruta de rollback. Si tratas cualquiera de ellos como opcional, un parche rutinario puede convertirse en un incidente de madrugada.

Table of Contents

El incidente de actualización de las 2 A.M. que dio origen a esta guía

El release pasó el CI y parecía normal. El viernes tarde, un desarrollador subió un build de Electron sin firmar, y el job de publish subió suficientes assets para que el release pareciera completo. La aplicación arrancó en testing, pero nadie había probado el flujo de update desde un build de producción instalado.

A las 2:08 a.m., PagerDuty alertó al ingeniero de guardia. Un nuevo flujo de autenticación falló para parte de la flota, y los usuarios que recibieron el update no podían iniciar sesión. Otros usuarios se quedaron en la versión anterior porque el updater no podía verificar ni instalar el artifact. Algunos clientes tenían un release roto, mientras que el resto de la flota ejecutaba una versión distinta sin explicación clara.

La investigación siguió estos cinco pasos:

  1. Revisar el feed del release. El binario existía, pero los metadatos esperados no establecían claramente qué clientes debían recibirlo. Un manifest es un contrato entre el release pipeline y los clientes instalados, no un detalle de upload opcional.
  2. Inspeccionar el firmado. La versión no se firmó correctamente, por lo que la verificación falló en las plataformas afectadas. El firmado debe bloquear la publicación si falta o es inválido.
  3. Comparar logs del cliente. Los errores de actualización nunca llegaron a la telemetría central. La aplicación ignoró el evento y siguió funcionando, dejando al equipo sin evidencia fiable.
  4. Revisar controles de rollout. No había canales internos ni cohortes escalonadas. Todos los clientes aptos usaron el mismo feed, por lo que el fallo se propagó sin puntos de contención.
  5. Buscar un rollback. El equipo no tenía un procedimiento probado para republicar la versión anterior o redirigir a los clientes lejos de la versión defectuosa.

La documentación oficial de Electron deja claros los límites de la plataforma. Linux no tiene soporte nativo para auto-update, and macOS update requests must satisfy los requisitos de App Transport Security. La documentación también señala que el firmado es un requisito previo para actualizaciones de macOS fiables y la verificación de releases. El documento de autoUpdater de Electron define las restricciones de API, mientras que el sistema de release debe aplicar los controles operativos necesarios.

Lección del postmortem: Un updater que no puede explicar qué pasó es un intento de instalación remota sin telemetría.

El coste fue más allá del tiempo de ingeniería. Los clientes perdieron la confianza en el cliente de escritorio, el equipo de soporte tuvo que explicar un comportamiento inconsistente y el equipo pasó la siguiente jornada reconstruyendo un proceso de release que debería haber existido antes del incidente.

Trata el auto-update como un sistema operacional. La firma es un gate de release, los manifests definen el contrato del cliente, los canales de rollout limitan la exposición y el rollback sigue siendo una ruta probada en lugar de un invento de emergencia.

Cómo elegir la ruta correcta de Electron Updater

A las 2 a. m., elegir el updater equivocado se convierte en un problema operativo. Una actualización de binario nativo debe gestionar la firma, los manifests, los instaladores y el rollback. Un cambio de JavaScript o CSS solo en el renderer sigue una ruta distinta. Las restricciones de hosting también importan: un proyecto pequeño alojado en GitHub no necesita los mismos controles de release que un servicio de distribución empresarial.

Para proyectos que usan electron-builder con publicación de artifacts firmados, electron-updater suele ser el default práctico. Su ecosistema cubre targets de publicación, manifests de release, descargas de artifacts e instalación en el siguiente arranque. Soporta varios modelos de hosting, pero tu equipo sigue siendo responsable de la firma, la disponibilidad del feed, la política de canales, los controles de rollout y el monitoreo. La integración de Electron updater para Capgo es relevante al evaluar un modelo de entrega híbrido para bundles de la capa web junto con lanzamientos nativos.

update-electron-app es ideal para equipos que buscan una integración ligera con GitHub Releases. Realiza comprobaciones al iniciar y luego en intervalos recurrentes, lo que simplifica la configuración pero ofrece menos flexibilidad para la selección avanzada de canales, despliegues graduales y reglas de rollback personalizadas. El paquete es adecuado para procesos de release pequeños, siempre que GitHub Releases y su disponibilidad se ajusten a tus necesidades operativas.

Opción Control de Hosting Soporte de Firma Canales y Rollouts Graduales Carga de Mantenimiento
electron-updater S3, GitHub, HTTPS genérico y otros targets de publicación Se integra con el firmado de releases Base sólida; la política suele estar en el feed Moderado
update-electron-app Flujos de GitHub Releases simples Usa el modelo de firmado de Electron Limitado sin servicios adicionales Bajo
Squirrel.Windows o Squirrel.Mac Flujo de distribución por plataforma Depende de los requisitos de firma Posible, pero requiere más infraestructura Moderado para apps legacy
Servicio personalizado Control total de manifests, auth, cohorts y feeds Tú gestionas la verificación y las llaves Máxima flexibilidad Alto
actualizaciones Live Update de Capgo Entrega gestionada para bundles de la capa web Usa su propio updater y modelo de entrega Segmentación de audiencia y entrega por canales Modelo operativo separado de updates del binario nativo

Un servicio personalizado como Hazel, Nuts o un feed interno es ideal cuando la autorización de releases, el targeting por tenant, los registros de auditoría o las reglas de despliegue reguladas justifican el coste de implementación. El compromiso es la gestión continua. Tu equipo deberá definir la semántica del manifest, proteger las llaves de firma, mantener la compatibilidad del cliente y testear fallos en downloads, releases rechazados y el comportamiento de rollback.

Live updates can ship renderer-only changes without rebuilding the native shell. They do not replace binary updates when Electron, native modules, permissions, or installer behavior changes. Usa electron-updater a menos que necesites una lógica de rollout personalizada. Si necesitas lógica personalizada, apóyate en las convenciones de manifiesto y artefactos existentes en lugar de recrear el comportamiento de download y differential-update. El camino fiable es aquel que tu equipo pueda observar, preparar y revertir bajo presión.

Implementación del flujo de actualización automática en el proceso principal

El proceso principal debe encargarse de las comprobaciones e instalación de actualizaciones. El renderer puede mostrar el estado, pero no debería decidir si una actualización del ejecutable es de confianza ni cuándo se cierra la aplicación.

Configura primero el target de publicación

Una configuración mínima de electron-builder podría quedar así:

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

Mantén separados los feeds de beta y stable. Un canal es una política de release, no una etiqueta en la UI. Cada canal debe apuntar al artifact firmado y al manifest correctos.

Programa comprobaciones y expón eventos de ciclo de vida

Llamar a checkForUpdates() solo durante el arranque es un error común en producción. Un usuario puede dejar la aplicación abierta durante días, por lo que el proceso principal necesita un intervalo controlado y una estrategia de reintentos que respete el modo 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;
  }
});

El comportamiento exacto del evento de actualización varía según la plataforma y la configuración de empaquetado, así que prueba desde artifacts instalados en lugar del modo desarrollo. La documentación de Electron también advierte sobre problemas de timing al arrancar en Windows, incluyendo el caso de primera ejecución de Squirrel. No dispares una comprobación de actualización antes de que la aplicación haya completado la inicialización específica de la plataforma.

Mantén informado al renderer sin bloquear el trabajo

El preload bridge debe exponer un API limitado:

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 de progreso en el renderer puede ser deliberadamente simple:

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.';
  }
});

Condiciona la instalación al consentimiento del usuario en producción, a menos que tu app tenga una razón de peso para reiniciarse de inmediato. Configura un isQuitting flag antes de quitAndInstall(), ya que de lo contrario los manejadores de cierre de ventana podrían impedir que el instalador tome el control.

Captura de pantalla de https://raw.githubusercontent.com/electron-userland/electron-builder/master/docs/electron-builder-autoupdate.png

Dos fallos merecen tests explícitos. Primero, un cliente ya en ejecución debe llamar a checkForUpdates() periódicamente, no solo al iniciar. Segundo, el error evento debe llegar a los logs y a la telemetría. Si la app lo ignora sin reportarlo, tu workflow de troubleshooting de la app empieza con conjeturas en lugar de evidencias.

Configurar CI/CD para releases y manifiestos firmados

El pipeline de release es la fuente de verdad de lo que instalan los usuarios. Un build local que funciona en la máquina de un desarrollador no demuestra que el binario, el manifest, la firma y el canal publicados describan la misma release.

El modelo de publish de Electron-builder espera que los metadatos de la release y el target de actualización vayan juntos. En muchas configuraciones, eso implica un artefacto como latest.yml para Windows y latest-mac.yml para macOS, junto con los paquetes específicos de la plataforma y los archivos blockmap. Un manifiesto ausente puede hacer que un binario perfectamente válido sea invisible para los clientes.

Haz explícita la firma en CI

Un patrón simplificado de GitHub Actions se ve así:

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 secrets específicos de la plataforma y mantén el material de firma fuera del repositorio. Un error de firma debe detener el job, no generar un fallback sin firmar que alguien suba manualmente.

Variable Propósito
CSC_LINK Certificado de macOS o referencia al certificado
CSC_KEY_PASSWORD Contraseña para el material de firma de macOS
WIN_CSC_LINK Certificado de Windows o referencia al certificado
AWS_ACCESS_KEY_ID Credencial de publicación con acceso limitado
AWS_SECRET_ACCESS_KEY Secret vinculado a la credencial de publicación

La configuración de publicación debe identificar el proveedor y el canal de forma consistente:

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

Antes de publicar, condiciona el job a la versión del paquete, el tag, el commit SHA y el resultado del smoke-test. Tras la publicación, verifica que el feed contenga el manifest esperado y que este apunte al artifact exacto generado por ese job. Esto guía de configuración de continuous integration es útil al formalizar esos checks, y los equipos que comparan la orquestación de pipelines también pueden beneficiarse al entender cuándo usar Jenkins y Ansible juntos.

Los comandos que suelen exponer un release incompleto son intencionadamente aburridos:

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

Esos checks no sustituyen a una prueba de instalación firmada. Pero sí detectan el error operativo de hacer upload de un binario sin los metadatos que los clientes necesitan para descubrirlo.

Rollouts, canales y estrategia de rollback

Un feed de lanzamientos debería actuar más como un objetivo de despliegue que como una carpeta de descargas. Mantén los canales, beta, y última e internos separados, cada uno respaldado por su propio manifiesto y conjunto de artefactos firmados. La promoción debe mover un release probado entre políticas, no sobrescribir un archivo mientras los clientes lo descargan.

La separación de canales también protege a producción de builds de prueba accidentales. El updater debe saber si un cliente pertenece a un grupo interno, a una audiencia beta o a la población estable antes de evaluar el feed.

Usa cohortes antes de una exposición amplia

Un campo personalizado en el manifiesto puede permitir una entrega escalonada:

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

El proceso principal puede asignar un bucket estable por usuario y luego compararlo con rolloutPercentage. La asignación estable es clave. Un usuario que oscila entre estados elegibles e inelegibles en cada comprobación tendrá un comportamiento impredecible, dificultando la interpretación de los reportes de soporte.

Expande el cohort solo después de que el release haya superado su ventana de observación. La ventana exacta debe reflejar tu patrón de uso, pero la decisión debe basarse en señales, no solo en el calendario. Rastrea resultados de update-check, descargas completadas, salud del lanzamiento, crashes, excepciones del renderer y éxito de autenticación.

Señal Acción Motivo
Errores de feed o firma superan el límite aprobado Detener despliegue Los clientes podrían no validar o detectar la versión
Fallan los checks tras la actualización Revertir feed El binario se instala pero falla al arrancar
Aumentan las excepciones del renderer tras la promoción Mantener en el cohort actual El instalador nativo puede estar bien, pero la nueva code no
Las señales se mantienen en el presupuesto de release Expandir el cohort La evidencia respalda una exposición más amplia

No confundas un rollback con borrar un artifact. Los clientes actuales pueden tener metadatos en caché y algunos ya podrían estar usando la versión errónea. Un plan de rollback requiere un release firmado previo, un cambio en el feed y un comportamiento del cliente que permita la recuperación.

Regla operativa: El ingeniero de guardia debe poder ejecutar el rollback sin reconstruir la aplicación durante el incidente.

En la práctica, el runbook debería promover el manifiesto de la versión anterior de vuelta al canal afectado, invalidar el marcador de staging y confirmar que los nuevos checks resuelven a la versión segura. Si el problema está en el renderer code y no en el shell nativo, un rollback dirigido a la capa web puede ser más rápido. Una plataforma como Capgo rollouts por fases puede ser relevante para esa capa de entrega independiente, pero no debe desdibujar el límite entre un rollback de binario nativo y uno de web-bundle.

Trata el auto-update como un control de seguridad

Un updater de Electron descarga el ejecutable code y puede instalarlo con mínima interacción del usuario. Eso convierte la ruta de actualización en un límite de seguridad, no solo en una función de conveniencia. La documentación oficial de Electron describe restricciones de la plataforma como macOS ATS, y la cobertura de seguridad ha documentado un escenario de 2022 en el que atacantes que controlaban la infraestructura de updates podían distribuir paquetes maliciosos que aún pasaban los checks de firma de code, como se analiza en la documentación de seguridad de auto-update de Electron Builder.

El firmado de Code sigue siendo fundamental, pero no es todo el modelo de confianza. Firma cada release, verifica el certificado y la identidad durante el CI, y mantén un procedimiento documentado de rotación de claves. En macOS, combina la firma con la notarización y el hardened runtime adecuado para tu aplicación. En Windows, haz auditables la propiedad del certificado, la renovación y el acceso al build. Linux requiere una estrategia específica por distribución, ya que Electron no ofrece un updater universal integrado.

Protege los metadatos con tanto cuidado como el binario

Un binario firmado aún puede asociarse con el release incorrecto si el canal de metadatos está comprometido o mal configurado. Considera añadir una firma de manifiesto verificada contra una clave pública embebida en la aplicación, exigir una versión mínima permitida y rechazar downgrades inesperados salvo que una ruta de recuperación autorizada los permita explícitamente.

El feed también merece controles de producción:

  • Restringe el acceso para publicar: Dale al CI solo los permisos necesarios para publicar los assets del release.
  • Protege los secrets de firmado: Guarda los certificados y claves privadas en un gestor de secrets, no en archivos del repositorio.
  • Fija las dependencias: Fija Electron, electron-builder y las dependencias transitivas en el CI.
  • Revisa los artifacts: Escanea los paquetes generados y compáralos con el commit y la versión previstos.
  • Exigir transporte seguro: Sigue los requisitos de ATS y HTTPS estrictos para las solicitudes de actualización.
  • Monitorear fallos de verificación: Trata los fallos repetidos de firma o manifiesto como eventos de seguridad, no como ruido de red normal.

El ecosistema de herramientas mantenidas de Electron sigue ampliando la cobertura de empaquetado y updater, pero el mantenimiento no elimina la necesidad de modelar amenazas. El objetivo práctico es asegurar que un atacante que comprometa un bucket, una CDN o un paso de build aún no pueda hacer que el cliente acepte un release no autorizado. La guía de verificación de firmas aporta contexto útil para diseñar esa capa de verificación adicional.

Diagrama de un proceso de actualización en producción de cuatro pasos que muestra la verificación, el despliegue gradual, el monitoreo de incidentes y los protocolos de rollback.

Runbook y checklist para actualizaciones en producción

Un release está listo solo cuando otro ingeniero puede operarlo bajo presión. Mantén la checklist cerca del job de deployment y del canal de incidentes.

Gates de pre-release

  • Identidad de versión: Confirma que la versión del paquete, el tag de release, el commit SHA y el changelog coinciden.
  • Firma: Verifica que cada artifact de plataforma esté firmado y que la notarización o validación equivalente haya terminado.
  • Contrato del manifiesto: Confirmar latest.yml, latest-mac.yml, hashes, rutas y blockmaps coinciden con los artifacts subidos.
  • Seguridad del channel: Publica en el feed interno o beta antes de promover el release channel.
  • Telemetría: Confirma que las comprobaciones de actualización, el progreso de descarga, la instalación, el inicio y los errores se reciben correctamente.

Canary y rollout completo

  • Control de cohortes: Empieza con una audiencia interna o beta muy reducida.
  • Presupuesto de salud: Detén la promoción si los fallos de lanzamiento, errores de descarga de actualizaciones, excepciones del renderer o fallos de autenticación superan los límites aprobados por el equipo.
  • Aprobación de promoción: Requiere una decisión explícita de go/no-go antes de pasar el release al feed estable.
  • Impacto en el cliente: Prepara los mensajes de soporte antes de la distribución masiva, no después del primer incidente.

Respuesta ante incidentes

Si el nuevo binario no arranca, falla el spawn de procesos o las descargas de updates dejan de completarse, detén la promoción de inmediato. Restaura el manifest firmado anterior, invalida el marcador de staging y verifica que los clientes nuevos resuelvan a la versión anterior. Luego confirma mediante telemetría que la flota se está recuperando antes de comunicar el cierre.

Los comandos exactos de rollback dependen de tu proveedor, pero la secuencia siempre debe estar documentada: cambia el manifest del channel a la versión anterior, invalida el tag de staging, publica un marcador de actualización forzada si la recuperación lo requiere y verifica la ruta de downgrade con telemetría en vivo. Un rollback que no ha sido probado es solo una esperanza.

Una infografía profesional con una checklist para gestionar actualizaciones de software en producción, incluyendo planificación, ejecución y validación post-update.


Capgo ofrece un updater para Electron que permite entregar cambios firmados en la capa web, canales específicos, controles de rollout y observabilidad de actualizaciones sin tener que hacer un Native Build por cada cambio en el renderer. Si quieres separar los lanzamientos de binarios nativos de la entrega controlada de JavaScript y CSS, visita Capgo y evalúalo junto con tu pipeline de lanzamientos de Electron actual.

Live updates para apps Capacitor

Cuando un bug de la capa web está en producción, publica el fix a través de Capgo en lugar de esperar días a la aprobación de la app store. Los usuarios reciben la actualización en segundo plano mientras los cambios nativos siguen el flujo de revisión habitual.

Lo último de nuestro blog

Capgo te da la información clave que necesitas para crear una app móvil realmente profesional.