System Design/02 - Componentes/Caching2 min
Client Caching
- Que problema isso resolve?
- Quando usar / quando NÃO usar?
- Qual o principal trade-off?
- Como isso falha em produção?
Conceito
Cache no próprio cliente — navegador, app móvel, SDK. É o cache mais rápido possível porque elimina a rede inteira.
Headers HTTP que controlam
| Header | Efeito |
|---|---|
Cache-Control: max-age=3600 |
Válido por 1 hora, sem perguntar |
Cache-Control: no-cache |
Pode guardar, mas revalide antes de usar |
Cache-Control: no-store |
Nunca guarde (dado sensível) |
Cache-Control: private |
Só o navegador; proxies e CDN não |
ETag / If-None-Match |
Revalidação: 304 Not Modified, sem corpo |
Last-Modified / If-Modified-Since |
Idem, por data |
immutable |
Nunca revalide — para conteúdo versionado |
Outros armazenamentos do cliente
localStorage e IndexedDB (persistentes), sessionStorage (por aba), Service Worker (controle programático, offline-first), e cache em memória do app.
Trade-offs
O ganho é absoluto: latência zero e carga zero no servidor.
O custo é que você perde o controle. Uma vez que o cliente guardou com max-age=86400, não existe forma de invalidar — nenhum purge alcança o navegador do usuário. Ele vai usar o dado velho pelo tempo que você declarou.
Isso torna o versionamento de URL essencial: app.a3f9c1.js com max-age=31536000, immutable é seguro precisamente porque o nome muda quando o conteúdo muda. Já app.js com um ano de cache é uma decisão que você não pode desfazer.
Dado sensível merece atenção especial: sem no-store, uma resposta com informação pessoal pode ficar no disco do cliente, acessível a quem usar a máquina depois.
E há o problema da diversidade: você não controla as versões de navegador nem as políticas de cache dos intermediários. Comportamento que funciona num ambiente pode divergir em outro.
Exemplo prático
Estratégia de cache de um SPA:
index.html → no-cache (revalida sempre; é o índice)
app.a3f9c1.js → max-age=31536000, immutable
estilo.7b2e.css → max-age=31536000, immutable
/api/* → no-store (dado do usuário)
O index.html é pequeno e revalida a cada visita — normalmente devolvendo 304. Quando há deploy, ele muda e passa a referenciar app.9d4f2b.js, um nome que o cliente nunca viu e que vai buscar.
Resultado: deploy propaga imediatamente, e todos os assets pesados vêm do disco local. O usuário baixa alguns bytes em vez de megabytes.
Relacionado
Parte de Caching · roadmap.sh/system-design