Uma aplicação offline-first consegue sobreviver à falta de rede. Uma aplicação local-first vai além: o dispositivo mantém uma cópia primária dos dados, lê e escreve localmente e sincroniza em segundo plano. A diferença parece pequena até duas pessoas editarem a mesma informação em aparelhos desconectados.
Mostrar uma tela sem internet é um problema de cache. Permitir trabalho real, preservar alterações e reconciliar cópias independentes transforma o navegador em parte de um sistema distribuído. É aí que o local-first deixa de ser uma melhoria de loading e vira arquitetura.
PWA, offline-first e local-first não são sinônimos
Uma PWA descreve capacidades de distribuição e integração, como instalação e service worker. Offline-first costuma manter o servidor como fonte de verdade, usando cache e filas para atravessar quedas de conexão. No local-first, a interface não espera confirmação remota para cada leitura ou escrita; o banco local é parte central do produto.
O trabalho original da Ink & Switch associa esse modelo a sete ideais, entre eles resposta rápida, funcionamento entre dispositivos, colaboração, longevidade, privacidade e controle dos dados pelo usuário. Não é uma receita fechada nem a promessa de eliminar servidores. O servidor pode continuar cuidando de sincronização, backup, autenticação e regras que precisam de autoridade central.
Onde os dados ficam no navegador
localStorage resolve preferências pequenas, mas é síncrono e limitado. IndexedDB oferece armazenamento estruturado e assíncrono. O Origin Private File System, ou OPFS, fornece arquivos privados ao origin e acesso otimizado, inclusive operações síncronas dentro de Web Workers. Isso tornou viável executar bancos como SQLite no navegador em cenários mais sérios.
Mesmo assim, armazenamento local não é um disco garantido para sempre. Quotas variam, o usuário pode limpar os dados do site e políticas de eviction podem agir sob pressão de espaço. A aplicação precisa solicitar persistência quando apropriado, acompanhar uso e manter uma estratégia de recuperação.
Sincronização é o produto invisível
Imagine que Ana altere o título de uma tarefa no celular sem rede enquanto Bruno muda o prazo no notebook. Uma mesclagem por campo pode preservar as duas alterações. Se ambos mudarem o título, o sistema precisa escolher uma regra, como last-write-wins, ou apresentar o conflito.
CRDTs são estruturas criadas para que mudanças concorrentes possam convergir sem coordenação central. Funcionam especialmente bem em colaboração de texto e outros domínios com operações combináveis. Não eliminam toda decisão: uma mesclagem matematicamente válida pode produzir um resultado sem sentido para o negócio.
Dois usuários reservarem o último item do estoque é um conflito semântico. Os registros podem se combinar perfeitamente e ainda violar a regra “não vender mais do que existe”. Pagamentos, inventário escasso e permissões críticas normalmente exigem uma autoridade central e consistência mais forte.
Local não significa automaticamente privado
Guardar a cópia principal no dispositivo pode aumentar controle e resiliência, mas a aplicação ainda pode enviar telemetria, sincronizar dados sem criptografia adequada ou expor informações a outros usuários do aparelho. Também precisa resolver logout, revogação de acesso e remoção de dados já replicados.
- Defina quais dados são locais, replicados e exclusivamente centrais.
- Modele conflitos por tipo de dado, não com uma regra universal.
- Projete exportação e recuperação antes de confiar no armazenamento local.
- Trate autenticação e autorização separadamente da disponibilidade offline.
- Teste reconexão, duplicação, mudanças fora de ordem e aparelhos com relógios divergentes.
Onde faz sentido começar
Editores, notas, ferramentas de campo e fluxos criativos se beneficiam de resposta imediata e trabalho sem rede. Dashboards cujos dados nascem no servidor, catálogos gigantes e operações transacionais fortes tendem a ser candidatos piores.
Também não é necessário converter o produto inteiro. Rascunhos locais, uma fila confiável de mutações ou um módulo colaborativo podem adotar princípios local-first dentro de uma aplicação tradicional. Essa fatia permite aprender sobre sincronização sem transformar cada tela em um experimento de sistemas distribuídos.
A experiência rápida chama atenção, mas o valor duradouro está em o usuário continuar dono do trabalho quando a rede ou o serviço falha. Para entregar isso, o spinner some da interface e reaparece, com muito mais responsabilidade, no desenho da sincronização.
Sincronize operações, não apenas a fotografia final
Um op-log local guarda cada mudança com ID, entidade, base conhecida e instante lógico. O cliente envia operações pendentes, recebe confirmações e depois busca mudanças remotas desde o último cursor. Repetir a mesma operação não pode aplicar o efeito duas vezes.
{
"operationId": "device-7:1842",
"entityId": "note-42",
"baseVersion": 18,
"type": "replace-title",
"value": "Planejamento",
"deviceTime": "2026-06-03T12:10:00Z"
}
deviceTime ajuda na interface, mas não deve decidir sozinho quem vence: relógios divergem. Use versão do servidor, vetor, CRDT ou uma regra de domínio conforme o tipo de dado. Um título pode aceitar last-write-wins; saldo e permissão exigem operação validada no servidor.
Exclusão precisa sobreviver ao offline
Apagar a linha no servidor faz um aparelho offline reaparecer com a cópia antiga. Tombstones mantêm a informação de exclusão até que todos os clientes relevantes tenham avançado além dela. A coleta desses marcadores precisa de uma política baseada em cursores ou retenção, não apenas idade.
O transporte pode usar polling, SSE ou WebSocket; nenhum deles resolve conflito. A entrega de mudanças locais pode combinar outbox e identificadores idempotentes para sobreviver a repetição.
- mostre estado pendente, sincronizado e em conflito;
- permita exportar ou recuperar dados antes de limpar armazenamento;
- no logout, remova chaves, filas e dados privados do usuário anterior;
- teste dois aparelhos editando e excluindo a mesma entidade;
- simule semanas offline e uma migração de schema.

