IndexedDB vs localStorage: qual armazenamento do navegador usar
IndexedDB vs localStorage
IndexedDB vs localStorage: limites, velocidade e quando usar | We.Inc
Compare IndexedDB e localStorage lado a lado: limites de tamanho por navegador, síncrono vs assíncrono, o que cada um consegue guardar e uma demo ao vivo que salva uma nota nos dois.
Escolha localStorage para algumas configurações pequenas: ele guarda só strings, cerca de 5 MiB por origem, e cada chamada trava a página até terminar. Escolha IndexedDB para dados de verdade: é assíncrono, transacional, guarda objetos, datas e arquivos, e a cota é uma fatia do disco. A demo abaixo grava uma nota nos dois.
A versão curta
Pergunta
localStorage
IndexedDB
O que ele guarda?
Só strings
Tudo o que o algoritmo de structured clone copia, incluindo Blob e File
Tamanho
Até 5 MiB por origem
Uma fatia do disco livre, definida por cada navegador
Trava a página?
Sim, toda chamada é síncrona
Não, os resultados chegam por eventos ou promises
Transações e índices
Não
Sim
Pode ser usado em um Web Worker
Não, é uma propriedade de window
Sim
Ideal para
Tema, última aba, um rascunho em texto
Dados offline, caches, arquivos, tudo o que você consulta
As duas APIs mantêm dados no navegador do visitante depois que a aba fecha, e as duas ficam restritas à origem da página. A diferença é o peso. localStorage é um pequeno mapa síncrono de strings que você aprende em um minuto; IndexedDB é um pequeno banco de dados com versões, object stores e transações. Esta página mostra os limites reais da documentação e deixa você ver o que cada um retorna.
Digite uma nota e clique em Salvar nos dois. A página grava a nota no localStorage como texto JSON e em um object store do IndexedDB como um objeto de verdade.
Clique em Ler de volta. O painel de resultado mostra o tipo que cada API retornou: uma string do localStorage, um objeto com um Date funcionando do IndexedDB.
Clique em Ver cota para perguntar ao navigator.storage.estimate() quanto esta origem usa e pode usar. Os números são estimativas.
Clique em Limpar dados da demo para remover a chave da demo e apagar o banco da demo. Nada sai do seu dispositivo.
Envolva localStorage.setItem em try...catch. Um armazenamento cheio lança QuotaExceededError, e algumas configurações de privacidade lançam SecurityError no primeiro acesso.
Guarde a saída de JSON.stringify no localStorage e faça o parse na leitura. Datas voltam como strings, então converta você mesmo.
Para IndexedDB, um wrapper pequeno como idb ou Dexie transforma o estilo de requests e eventos em promises e poupa muito código repetitivo.
Chame navigator.storage.persist() só para dados que a pessoa ficaria chateada de perder, como documentos offline. Caso contrário, o navegador pode removê-los quando faltar espaço.
Nunca guarde segredos ou tokens de sessão em nenhum dos dois. Qualquer script rodando na página consegue lê-los.
Perguntas frequentes
Quanto cabe no localStorage?
A MDN documenta um limite de 5 MiB de local storage e 5 MiB de session storage por origem, 10 MiB no total. Como os valores são strings UTF-16, a quantidade de caracteres que cabe pode ser menor do que você espera. Passar do limite lança um QuotaExceededError.
Quanto cabe no IndexedDB?
Depende do navegador e do disco. Navegadores Chromium permitem a uma origem até 60% do tamanho total do disco. O Firefox permite o menor entre 10% do disco ou 10 GiB por grupo de sites no modo best-effort. O app de navegador Safari permite cerca de 60% do disco. Use navigator.storage.estimate() para ler o número real.
IndexedDB é mais rápido que localStorage?
Para um único valor pequeno, localStorage costuma ser mais rápido de escrever no código e rápido o bastante para executar. O problema é que ele é síncrono, então leituras e gravações grandes congelam a thread principal. O IndexedDB faz o trabalho fora do fluxo principal e avisa quando termina, o que mantém a rolagem e a digitação fluidas.
O navegador pode apagar meus dados do IndexedDB?
Sim. Por padrão o armazenamento é best-effort, então o navegador pode remover os dados de uma origem quando o disco está apertado. Chamar navigator.storage.persist() muda para o modo persistente, em que só a pessoa pode limpá-los. O Firefox mostra um pedido de permissão; o Chrome e o Safari decidem pela forma como a pessoa usa o site.
Devo usar localStorage para um token de login?
Não. Qualquer script na página, inclusive um injetado, consegue ler o localStorage e o IndexedDB. Guarde identificadores de sessão em cookies marcados como HttpOnly, Secure e SameSite, que os scripts da página não conseguem ler.
Por que ser síncrono importa
Quando o código chama localStorage.getItem, o navegador para de executar outro JavaScript até o valor voltar do disco. Para o nome de um tema ninguém percebe. Para alguns megabytes de JSON processados a cada carregamento de página, isso aparece como uma pausa antes de a página responder aos toques.
O IndexedDB devolve na hora um objeto de request e dispara success ou error depois. Esse formato exige mais código, e é por isso que a maioria dos projetos usa um wrapper com promises, mas ele nunca deixa a página refém.
Strings vs structured clone
O localStorage transforma tudo em texto. Guarde o número 3 e você lê de volta a string "3"; guarde um objeto sem JSON.stringify e você lê de volta "[object Object]".
O IndexedDB copia valores com o algoritmo de structured clone, então um Date continua Date, um Map continua Map, e um Blob ou File pode ser salvo como está. É isso que o torna adequado para imagens offline, áudio gravado ou rascunhos com anexos.
Uma regra simples para escolher
Se o dado cabe em uma linha curta e você o lê uma vez na inicialização, localStorage serve. Se você gostaria de pesquisar, contar, paginar, guardar arquivos binários ou atualizar os dados a partir de um service worker, use IndexedDB.
Dados no servidor são uma terceira opção que muitas vezes supera as duas: se a pessoa espera ver a mesma coisa em outro dispositivo, o lugar disso é o seu banco de dados, com o armazenamento do navegador só como cache.
Limites de armazenamento por navegador
Números conforme documentados na página de cotas de armazenamento da MDN. IndexedDB, a Cache API e o origin private file system compartilham a mesma cota.
Cota por origem
Navegador
localStorage
IndexedDB (best-effort)
IndexedDB (persistente)
Chrome, Edge e outros Chromium
5 MiB
Até 60% do disco total
Até 60% do disco total
Firefox
5 MiB
O menor entre 10% do disco ou 10 GiB por grupo de sites
Até 50% do disco, com limite de 8 TiB
App de navegador Safari
5 MiB
Cerca de 60% do disco total
Cerca de 60% do disco total
Apps que incorporam conteúdo web (WebKit)
5 MiB
Cerca de 15% do disco total
Cerca de 15% do disco total
O mesmo salvamento nas duas APIs
localStorage: stringify, proteção, parse
O try...catch trata um armazenamento cheio ou bloqueado. A data precisa ser reconstruída à mão depois do parse.
IndexedDB: abrir, atualizar, gravar em uma transação
onupgradeneeded roda na primeira vez e sempre que o número da versão aumenta; é o único lugar onde se criam object stores.
Pergunte quanto espaço você tem e peça para mantê-lo
estimate() retorna contagens aproximadas de bytes. persist() resolve como true se o navegador concedeu armazenamento persistente.
Salve uma nota nos dois armazenamentos
Esta demo roda só no seu navegador. Ela grava na chave we-demo-note e em um banco chamado we-demo-db, e o botão Limpar remove os dois.
Nota para salvar
Ligar para a gráfica na sexta
Salvar nos dois
Ler de volta
Ver cota
Limpar dados da demo
Nada lido ainda. Salve uma nota e depois clique em Ler de volta.
O localStorage retornou
O IndexedDB retornou
Tipo: {v}
savedAt é um Date: {v}
Nada armazenado
Nota salva no localStorage e no IndexedDB.
Chave e banco da demo removidos.
Esta origem usa cerca de {n} MB de aproximadamente {v} MB disponíveis.
Este navegador não oferece navigator.storage.estimate().