IndexedDB vs localStorage: qué almacenamiento del navegador usar
IndexedDB vs localStorage
IndexedDB vs localStorage: límites, velocidad y cuándo usarlos | We.Inc
Compara IndexedDB y localStorage lado a lado: límites de tamaño por navegador, síncrono frente a asíncrono, qué puede guardar cada uno y una demo en vivo que guarda una nota en ambos.
Elige localStorage para unos pocos ajustes pequeños: solo guarda cadenas, unos 5 MiB por origen, y cada llamada bloquea la página hasta que termina. Elige IndexedDB para datos de verdad: es asíncrono, transaccional, guarda objetos, fechas y archivos, y su cuota es una parte del disco. La demo de abajo escribe una nota en ambos.
La versión corta
Pregunta
localStorage
IndexedDB
¿Qué puede guardar?
Solo cadenas
Todo lo que copia el algoritmo de clonado estructurado, incluidos Blob y File
Tamaño
Hasta 5 MiB por origen
Una parte del disco libre, decidida por cada navegador
¿Bloquea la página?
Sí, cada llamada es síncrona
No, los resultados llegan mediante eventos o promesas
Transacciones e índices
No
Sí
Se puede usar en un Web Worker
No, es una propiedad de window
Sí
Ideal para
Tema, última pestaña, un borrador en texto
Datos sin conexión, cachés, archivos, todo lo que consultes
Ambas API conservan los datos en el navegador del visitante después de cerrar la pestaña, y ambas están limitadas al origen de la página. La diferencia es el peso. localStorage es un pequeño mapa síncrono de cadenas que aprendes en un minuto; IndexedDB es una pequeña base de datos con versiones, almacenes de objetos y transacciones. Esta página muestra los límites reales de la documentación y te deja ver qué devuelve cada una.
Escribe una nota y pulsa Guardar en ambos. La página la escribe en localStorage como texto JSON y en un almacén de objetos de IndexedDB como un objeto real.
Pulsa Leer de nuevo. El panel de resultados muestra el tipo que devolvió cada API: una cadena desde localStorage y un objeto con un Date funcional desde IndexedDB.
Pulsa Comprobar cuota para preguntar a navigator.storage.estimate() cuánto usa y puede usar este origen. Las cifras son estimaciones.
Pulsa Borrar datos de la demo para eliminar la clave de la demo y borrar la base de datos de la demo. Nada sale de tu dispositivo.
Envuelve localStorage.setItem en un try...catch. Un almacén lleno lanza QuotaExceededError, y algunos ajustes de privacidad lanzan SecurityError en el primer acceso.
Guarda en localStorage la salida de JSON.stringify y analízala al leer. Las fechas vuelven como cadenas, así que conviértelas tú.
Para IndexedDB, un pequeño envoltorio como idb o Dexie convierte el estilo de peticiones y eventos en promesas y te ahorra mucho código repetitivo.
Recurre a navigator.storage.persist() solo para datos que a la persona le molestaría perder, como documentos sin conexión. Si no, el navegador puede expulsarlos cuando falte espacio.
Nunca guardes secretos ni tokens de sesión en ninguno de los dos. Cualquier script que se ejecute en la página puede leerlos.
Preguntas frecuentes
¿Cuánto puede guardar localStorage?
MDN documenta un límite de 5 MiB de almacenamiento local y 5 MiB de almacenamiento de sesión por origen, 10 MiB en total. Como los valores son cadenas UTF-16, el número de caracteres que caben puede ser menor de lo que esperas. Superar el límite lanza un QuotaExceededError.
¿Cuánto puede guardar IndexedDB?
Depende del navegador y del disco. Los navegadores Chromium permiten a un origen hasta el 60% del tamaño total del disco. Firefox permite lo menor entre el 10% del disco o 10 GiB por grupo de sitios en modo best-effort. Las apps del navegador Safari permiten alrededor del 60% del disco. Usa navigator.storage.estimate() para leer la cifra real.
¿Es IndexedDB más rápido que localStorage?
Para un único valor pequeño, localStorage suele ser más rápido de escribir en código y lo bastante rápido al ejecutarse. El problema es que es síncrono, así que las lecturas y escrituras grandes congelan el hilo principal. IndexedDB hace el trabajo fuera del flujo principal y te avisa cuando termina, lo que mantiene fluidos el desplazamiento y la escritura.
¿Puede el navegador borrar mis datos de IndexedDB?
Sí. Por defecto el almacenamiento es best-effort, así que el navegador puede expulsar los datos de un origen cuando el disco va justo. Pedir navigator.storage.persist() cambia al modo persistente, en el que solo la persona puede borrarlos. Firefox muestra una solicitud de permiso; Chrome y Safari deciden según cómo use la persona el sitio.
¿Debo usar localStorage para un token de inicio de sesión?
No. Cualquier script de la página, incluido uno inyectado, puede leer localStorage e IndexedDB. Guarda los identificadores de sesión en cookies marcadas como HttpOnly, Secure y SameSite, que los scripts de la página no pueden leer.
Por qué importa que sea síncrono
Cuando el código invoca localStorage.getItem, el navegador deja de ejecutar otro JavaScript hasta que el valor vuelve del disco. Con el nombre de un tema nadie lo nota. Con unos cuantos megabytes de JSON analizados en cada carga de página, se nota como una pausa antes de que la página responda a los toques.
IndexedDB devuelve al instante un objeto de petición y dispara success o error más tarde. Esa forma obliga a escribir más código, por eso la mayoría de proyectos usa un envoltorio con promesas, pero nunca tiene la página secuestrada.
Cadenas frente a clonado estructurado
localStorage convierte todo en texto. Guarda el número 3 y leerás la cadena "3"; guarda un objeto sin JSON.stringify y leerás "[object Object]".
IndexedDB copia los valores con el algoritmo de clonado estructurado, así que un Date sigue siendo un Date, un Map sigue siendo un Map, y un Blob o un File se pueden guardar tal cual. Eso es lo que lo hace adecuado para imágenes sin conexión, audio grabado o borradores con adjuntos.
Una regla sencilla para elegir
Si los datos caben en una línea corta y los lees una vez al arrancar, localStorage sirve. Si quisieras buscar en ellos, contarlos, paginarlos, guardar archivos binarios o actualizarlos desde un service worker, usa IndexedDB.
Los datos en el servidor son una tercera opción que a menudo supera a ambos: si la persona espera ver lo mismo en otro dispositivo, eso va en tu base de datos, con el almacenamiento del navegador solo como caché.
Límites de almacenamiento por navegador
Cifras según la página de cuotas de almacenamiento de MDN. IndexedDB, la Cache API y el sistema de archivos privado del origen comparten la misma cuota.
Cuota por origen
Navegador
localStorage
IndexedDB (best-effort)
IndexedDB (persistente)
Chrome, Edge y otros Chromium
5 MiB
Hasta el 60% del disco total
Hasta el 60% del disco total
Firefox
5 MiB
Lo menor entre el 10% del disco o 10 GiB por grupo de sitios
Hasta el 50% del disco, con un máximo de 8 TiB
App del navegador Safari
5 MiB
Alrededor del 60% del disco total
Alrededor del 60% del disco total
Apps que insertan contenido web (WebKit)
5 MiB
Alrededor del 15% del disco total
Alrededor del 15% del disco total
El mismo guardado en ambas API
localStorage: stringify, protección y parse
El try...catch gestiona un almacén lleno o bloqueado. La fecha hay que reconstruirla a mano después de analizarla.
IndexedDB: abrir, actualizar y escribir en una transacción
onupgradeneeded se ejecuta la primera vez y cada vez que sube el número de versión; es el único sitio donde se crean almacenes de objetos.
Pregunta cuánto espacio tienes y pide conservarlo
estimate() devuelve recuentos aproximados de bytes. persist() se resuelve como true si el navegador concedió almacenamiento persistente.
Guarda una nota en ambos almacenes
Esta demo se ejecuta solo en tu navegador. Escribe bajo la clave we-demo-note y en una base de datos llamada we-demo-db, y el botón Borrar elimina ambas.
Nota para guardar
Telefonear a la imprenta el viernes
Guardar en ambos
Leer de nuevo
Comprobar cuota
Borrar datos de la demo
Todavía no se ha leído nada. Guarda una nota y pulsa Leer de nuevo.
localStorage devolvió
IndexedDB devolvió
Tipo: {v}
savedAt es un Date: {v}
No hay nada guardado
Nota guardada en localStorage e IndexedDB.
Clave y base de datos de la demo eliminadas.
Este origen usa unos {n} MB de aproximadamente {v} MB disponibles.
Este navegador no ofrece navigator.storage.estimate().