O browser oferece três mecanismos de armazenamento simples: cookies (enviados ao servidor em cada request; criptográficos com HttpOnly/Secure/SameSite), localStorage (persistente, ~5-10MB, síncrono) e sessionStorage (limpo ao fechar a aba, ~5-10MB, síncrono). Para dados estruturados grandes ou offline, use IndexedDB. Para assets cacheados, use Cache API (Service Worker).
Comparativo geral
Cookies
localStorage
sessionStorage
IndexedDB
Capacidade
4KB
~5-10MB
~5-10MB
Centenas de MB
Enviado ao servidor
Sim (automático)
Não
Não
Não
Escopo
Domínio + caminho
Origem
Aba + origem
Origem
Persistência
Configurável
Até limpar
Fecha a aba
Até limpar
API
Síncrona (string)
Síncrona (string)
Síncrona (string)
Assíncrona
Acesso via JS
Configurável (HttpOnly)
Sim
Sim
Sim
localStorage e sessionStorage
// Ambos têm a mesma API — só diferem em escopo/persistência// Escrever (sempre serializado como string)localStorage.setItem('user', JSON.stringify({ name: 'Alice', role: 'admin' }));localStorage.setItem('count', '42');// Lerconst raw = localStorage.getItem('user'); // string ou nullconst user = raw ? JSON.parse(raw) : null;// Verificar existêncialocalStorage.getItem('key') !== null;// RemoverlocalStorage.removeItem('user');// Limpar tudolocalStorage.clear();// Iterar sobre todas as chavesfor (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); const value = localStorage.getItem(key); console.log(key, value);}// ou usando spread (não é iterável diretamente)Object.entries(localStorage).forEach(([key, value]) => console.log(key, value));
// Dispara em OUTRAS abas da mesma origem quando localStorage mudawindow.addEventListener('storage', (event) => { event.key; // chave alterada (null se foi .clear()) event.oldValue; // valor anterior (string ou null) event.newValue; // novo valor (string ou null; null se foi removido) event.url; // URL da aba que fez a mudança event.storageArea; // localStorage ou sessionStorage if (event.key === 'cart') { syncCart(JSON.parse(event.newValue ?? '[]')); }});
Não dispara na própria aba
O evento storage só é disparado em outras abas/janelas — não na que fez a mudança. Para comunicação na mesma aba, use variáveis normais ou eventos customizados. Para comunicação entre abas mais robusta, veja BroadcastChannel (nota Workers 02).
Cookies
Cookies são enviados automaticamente em cada HTTP request — ideal para autenticação (session token). Mas têm apenas 4KB e não devem armazenar dados sensíveis sem HttpOnly.
// API de cookies é minimalista e inconveniente// Ler todos os cookies (como string "key=val; key2=val2")document.cookie; // não tem getter por chave!// Escrever um cookie (NÃO substitui todos — adiciona/atualiza o especificado)document.cookie = 'nome=Alice; max-age=3600; path=/; samesite=strict';// Parser manualfunction getCookie(name) { return document.cookie .split('; ') .find(row => row.startsWith(name + '=')) ?.split('=')[1];}// Deletar (setar max-age=0 ou data no passado)document.cookie = 'nome=; max-age=0; path=/';
Atributos de cookies importantes
document.cookie = [ 'session=abc123', 'max-age=86400', // segundos; ou: 'expires=Fri, 31 Dec 2026 23:59:59 GMT' 'path=/', // path que pode ler o cookie (padrão: path atual) 'domain=.exemplo.com', // subdomínios inclusos (atenção: Cross-Site) 'secure', // só HTTPS 'samesite=strict', // 'strict' | 'lax' | 'none'].join('; ');
Atributo
Efeito
HttpOnly
Só acessível pelo servidor (via Set-Cookie header), JS não lê — proteção XSS
Secure
Só enviado em HTTPS
SameSite=Strict
Nunca enviado em requests cross-site
SameSite=Lax
Enviado em navegação top-level; bloqueado em requests cross-site silenciosos
SameSite=None; Secure
Enviado sempre (cookies de terceiros) — exige Secure
max-age=0
Apagar o cookie
Cookie Store API (moderno)
A Cookie Store API (cookieStore) oferece uma interface async e ergonômica — substitui document.cookie:
Suporte crescente (Chrome 87+, mas não Firefox ainda em 2024).
Quando usar o quê
Precisa ser enviado ao servidor? → Cookie (com HttpOnly + SameSite)
Dado simples, pequeno, persistente? → localStorage (com JSON.stringify/parse)
Dado de sessão (limpar ao fechar aba)? → sessionStorage
Dados estruturados, grandes, ou queries? → IndexedDB
Assets para uso offline? → Cache API (Service Worker)
Para fixar
Por que cookies são enviados automaticamente ao servidor mas localStorage não?
O que acontece se você salvar um objeto no localStorage sem JSON.stringify?
O evento storage dispara na aba que fez a mudança? Como isso afeta o design?
O que SameSite=Strict faz? Quando você usaria SameSite=Lax?
Por que HttpOnly protege contra XSS? O que um script malicioso poderia fazer sem esse atributo?