
Auto-update em apps desktop: Electron Forge
Distribuir um app desktop sem mecanismo de auto-update é assinar um contrato com o caos futuro. Em seis meses, você vai ter usuários em cinco versões diferentes do app, cada uma com bugs diferentes, comportamentos diferentes, e pedindo suporte para problemas que já foram resolvidos há semanas. Rastrear qual versão cada cliente está usando e convencê-los a atualizar manualmente é um trabalho que não deveria existir.
O auto-update bem implementado elimina esse problema na raiz. O usuário instala uma vez. A partir daí, o app se mantém atualizado silenciosamente em segundo plano — ou com uma notificação discreta quando uma atualização está disponível. A base de usuários converge para a versão mais recente em dias, não em meses.
A boa notícia é que o ecossistema Electron tem uma solução madura para isso: electron-updater, que funciona com GitHub Releases como servidor de distribuição. A má notícia é que implementar corretamente — com canais de release, rollout gradual e estratégia de rollback — exige mais cuidado do que o exemplo básico da documentação sugere.
electron-updater: Setup Básico com GitHub Releases
O electron-updater é parte do pacote electron-builder e é a solução mais usada para auto-update em apps Electron. Ele verifica periodicamente se há uma nova versão disponível em um servidor de atualização — que pode ser GitHub Releases, S3, ou um servidor próprio.
O setup inicial exige configuração no package.json e no main process:
// main.js — configuração do auto-updater
const { autoUpdater } = require('electron-updater')
const { ipcMain, dialog } = require('electron')
const log = require('electron-log')
// Configurar logging para diagnóstico
autoUpdater.logger = log
autoUpdater.logger.transports.file.level = 'info'
// Desabilitar auto-download para controlar quando instalar
autoUpdater.autoDownload = false
function setupAutoUpdater(mainWindow) {
// Verificar atualizações ao iniciar (com delay de 3 segundos)
setTimeout(() => {
autoUpdater.checkForUpdates()
}, 3000)
// Verificar novamente a cada 4 horas
setInterval(() => {
autoUpdater.checkForUpdates()
}, 4 * 60 * 60 * 1000)
autoUpdater.on('update-available', (info) => {
// Notificar o renderer process
mainWindow.webContents.send('update-available', info)
})
autoUpdater.on('download-progress', (progress) => {
mainWindow.webContents.send('download-progress', progress)
})
autoUpdater.on('update-downloaded', (info) => {
mainWindow.webContents.send('update-downloaded', info)
})
// Iniciar download quando usuário confirmar
ipcMain.on('start-download', () => {
autoUpdater.downloadUpdate()
})
// Instalar e reiniciar quando usuário confirmar
ipcMain.on('install-update', () => {
autoUpdater.quitAndInstall(false, true)
})
}
module.exports = { setupAutoUpdater }
A configuração no package.json define o servidor de publicação:
{
"build": {
"publish": {
"provider": "github",
"owner": "seu-usuario",
"repo": "seu-repositorio",
"private": false
}
}
}
Com essa configuração, ao publicar um GitHub Release com os artefatos de build, o electron-updater detecta automaticamente a nova versão e inicia o processo de atualização.
Release Channels: Stable, Beta e Nightly
Um único canal de release não é suficiente para a maioria dos projetos sérios. A prática padrão da indústria é ter pelo menos dois canais: stable para a base de usuários em produção, e beta para testadores que aceitam receber versões não finalizadas em troca de acesso antecipado a novidades.
O electron-updater suporta canais nativamente. A versão no package.json define o canal:
1.0.0— versão stable1.1.0-beta.1— versão beta1.1.0-alpha.1— versão alpha/nightly
No código, o canal pode ser configurado dinamicamente com base em uma preferência do usuário:
// Ler preferência de canal salva nas configurações
const channel = store.get('updateChannel', 'stable')
autoUpdater.channel = channel
// No UI de configurações, permitir ao usuário trocar de canal
ipcMain.on('set-update-channel', (event, newChannel) => {
store.set('updateChannel', newChannel)
autoUpdater.channel = newChannel
autoUpdater.checkForUpdates()
})
A comunicação do canal com a audiência certa é importante: usuários que optaram pelo canal beta sabem que podem receber versões com bugs ocasionais. Isso segmenta o feedback e permite identificar problemas antes que afetem toda a base de usuários.
Staging de Updates: Rollout Gradual por Porcentagem
Para aplicações com base de usuários grande, lançar uma versão para todos simultaneamente é arriscado. Um bug crítico que passe pelos testes vai afetar todos os usuários ao mesmo tempo.
O rollout gradual — lançar para 5% dos usuários primeiro, observar métricas por 24 horas, depois expandir para 20%, 50% e 100% — é uma prática padrão para mitigar esse risco.
O electron-updater não tem suporte nativo a rollout percentual, mas é possível implementar com lógica no servidor ou com uma camada de feature flag:
// Estratégia: verificar flag de rollout antes de iniciar update
autoUpdater.on('update-available', async (info) => {
// Gerar um identificador único estável para a instância
const instanceId = getOrCreateInstanceId()
// Consultar servidor para verificar se esta instância está no rollout
try {
const response = await fetch(
`https://api.seuapp.com/update-eligibility?version=${info.version}&instanceId=${instanceId}`
)
const { eligible } = await response.json()
if (eligible) {
mainWindow.webContents.send('update-available', info)
}
} catch {
// Em caso de falha na verificação, não bloquear o update
mainWindow.webContents.send('update-available', info)
}
})
O servidor controla a porcentagem de instâncias elegíveis para cada versão, permitindo aumentar gradualmente o rollout conforme a confiança na versão aumenta.
Rollback: Como Reverter uma Versão Problemática
Nenhum processo de QA é perfeito. Eventualmente uma versão problemática vai chegar aos usuários. Ter um mecanismo de rollback — seja automático ou manual — é a diferença entre um incidente controlado e uma crise de suporte.
A estratégia mais simples é manter a versão anterior disponível no GitHub Releases e redirecionar o servidor de updates para ela quando necessário. Se o latest.yml (arquivo que o electron-updater consulta) apontar para a versão anterior, as instâncias que ainda não atualizaram não vão receber a versão problemática.
Para usuários que já instalaram a versão com problema, a abordagem mais eficaz é publicar uma nova versão corrigida — mesmo que seja um hotfix mínimo — o mais rápido possível. O auto-update então substitui a versão problemática pela corrigida.
Em casos críticos, onde o app está crashando ao iniciar e o auto-update não consegue ser executado, é necessário ter um procedimento manual documentado. Isso inclui manter os instaladores de versões anteriores disponíveis para download direto e ter um canal de comunicação com usuários afetados.
O ponto mais importante sobre rollback é: planeje antes de precisar. Quando há um incidente em produção não é o momento de descobrir que o processo de rollback não foi testado.
Conclusão com CTA
Auto-update bem implementado não é um detalhe de distribuição — é parte da experiência do produto. Usuários que nunca precisam se preocupar em atualizar o app manualmente têm menos fricção no dia a dia. Equipes de desenvolvimento que podem lançar atualizações com confiança, sabendo que têm canais de staging e rollback, constroem com mais agilidade.
A complexidade real está nos detalhes: assinar os instaladores corretamente (sem assinatura de código o Windows bloqueia updates), lidar com usuários que deixam o computador ligado sem reiniciar, comunicar updates críticos de segurança de forma urgente mas sem ser intrusivo.
Na SystemForge, o auto-update com channels, staged rollout e capacidade de rollback faz parte do baseline de qualquer app desktop que construímos. Se você está desenvolvendo um app Electron e quer implementar uma estratégia de atualização robusta desde o início, podemos ajudar a estruturar isso corretamente.
Precisa de Software Desktop?
Desenvolvemos aplicativos desktop multiplataforma com Electron ou Tauri.
Saiba mais →Precisa de ajuda?

