Las aplicaciones web necesitan almacenar datos en el lado del cliente: preferencias del usuario, tokens de autenticación, datos cacheados, contenidos del carrito de compras, borradores de formularios. Los navegadores ofrecen varios mecanismos de almacenamiento, cada uno con características distintas. Elegir el incorrecto puede generar cuellos de botella en el rendimiento, vulnerabilidades de seguridad o pérdida de datos.
Comparación Rápida
Característica localStorage sessionStorage Cookies IndexedDB ────────────────────────────────────────────────────────────────────────────── Capacidad 5-10 MB 5-10 MB ~4 KB/cookie 100MB+ Persistencia Permanente Vida de la pestaña Configurable Permanente Enviado al servidor No No Sí (cada req) No Acceso JS Síncrono JS Síncrono JS + HTTP JS Asíncrono Formato de datos Cadena Cadena Cadena Cualquiera (objetos) Caso de uso Preferencias Estado temporal Tokens de autenticación Datos grandes
localStorage
Almacena pares clave-valor sin fecha de expiración. Los datos persisten hasta que son explícitamente borrados por el usuario o por tu código.
// Almacenar datos (solo cadenas)
localStorage.setItem('tema', 'oscuro');
localStorage.setItem('usuario', JSON.stringify({ nombre: 'Ana', id: 123 }));
// Recuperar datos
const tema = localStorage.getItem('tema'); // "oscuro"
const usuario = JSON.parse(localStorage.getItem('usuario'));
// Eliminar un elemento específico
localStorage.removeItem('tema');
// Borrar todos los datos
localStorage.clear();
// Comprobar uso del almacenamiento
const used = new Blob(Object.values(localStorage)).size;
console.log(`${(used / 1024).toFixed(1)} KB utilizados`);
Ideal para: Preferencias de tema, elección de idioma, estado de la interfaz de usuario (barra lateral abierta/cerrada), configuraciones no sensibles.
⚠️ Nunca almacenes: Tokens de autenticación, contraseñas, ni ningún dato sensible. localStorage es accesible para todo el JavaScript en la página, incluidos los scripts inyectados por XSS.
sessionStorage
API idéntica a localStorage, pero los datos están limitados a la pestaña actual del navegador y se borran cuando la pestaña se cierra.
// Almacenar datos de formulario (recuperables en navegación accidental)
const datosFormulario = { nombre: inputNombre.value, email: inputEmail.value };
sessionStorage.setItem('borradorFormulario', JSON.stringify(datosFormulario));
// Restaurar al cargar la página
window.addEventListener('load', () => {
const borrador = sessionStorage.getItem('borradorFormulario');
if (borrador) {
const { nombre, email } = JSON.parse(borrador);
inputNombre.value = nombre;
inputEmail.value = email;
}
});
Ideal para: Datos de formularios de varios pasos, estado temporal de asistentes, datos por pestaña que no deben filtrarse entre pestañas.
Cookies
El mecanismo de almacenamiento más antiguo. A diferencia de localStorage, las cookies se envían al servidor con cada solicitud HTTP, lo que las hace ideales para la autenticación pero terribles para el almacenamiento de grandes cantidades de datos.
// Establecer una cookie (lado del servidor — Express.js)
res.cookie('session_id', 'abc123', {
httpOnly: true, // JavaScript no puede acceder a esta cookie (protección XSS)
secure: true, // Solo se envía a través de HTTPS
sameSite: 'Lax', // Protección CSRF
maxAge: 86400000, // Expira en 24 horas (milisegundos)
path: '/',
});
// Establecer una cookie (JavaScript del lado del cliente)
document.cookie = "tema=oscuro; path=/; max-age=31536000; SameSite=Lax";
// Leer cookies (lado del cliente) — API incómoda
const tema = document.cookie
.split('; ')
.find(row => row.startsWith('tema='))
?.split('=')[1]; // "oscuro"
Ideal para: IDs de sesión, tokens de autenticación (con httpOnly + secure + sameSite).
⚠️ Indicadores de cookie importantes:
httpOnly— No puede ser leída por JavaScript (previene el robo de tokens XSS)secure— Solo se envía a través de HTTPSsameSite=Lax|Strict— Protección CSRF
IndexedDB
Una base de datos completa en el lado del cliente. Almacena datos estructurados (objetos, archivos, blobs) con índices para consultas. API asíncrona. Capacidad de cientos de megabytes.
// Abrir base de datos
const request = indexedDB.open('MiApp', 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
const store = db.createObjectStore('productos', { keyPath: 'id' });
store.createIndex('categoria', 'categoria', { unique: false });
};
request.onsuccess = (event) => {
const db = event.target.result;
// Añadir datos
const tx = db.transaction('productos', 'readwrite');
tx.objectStore('productos').add({
id: 1,
nombre: 'Herramienta',
categoria: 'utensilios',
precio: 29.99,
});
// Leer datos
const getTx = db.transaction('productos', 'readonly');
const getReq = getTx.objectStore('productos').get(1);
getReq.onsuccess = () => console.log(getReq.result);
};
Ideal para: Aplicaciones con capacidad offline, caché de grandes conjuntos de datos, almacenamiento de archivos/blobs, Progressive Web Apps (PWAs).
Guía de Decisión
- ¿Preferencias de tema/idioma? → localStorage
- ¿Datos de borrador de formulario? → sessionStorage
- ¿Sesión de autenticación? → Cookie HttpOnly Segura
- ¿Carrito de compras? → localStorage (invitado) o lado del servidor (iniciado sesión)
- ¿Caché de datos offline? → IndexedDB
- ¿Almacenamiento de archivos grandes? → IndexedDB
- ¿Datos necesarios por el servidor? → Cookie
Prueba Nuestras Herramientas Gratuitas para Desarrolladores
Codifica y decodifica datos para el almacenamiento del lado del cliente.