Skip to content

L65 - localStorage y sessionStorage

localStorage y sessionStorage son APIs del navegador que permiten almacenar datos de forma persistente en el cliente (en el disco del usuario). Ambas forman parte de la Web Storage API y proporcionan un almacenamiento clave-valor (strings) con un límite de ~5MB por dominio.

CaracterísticalocalStoragesessionStorage
PersistenciaPersiste hasta que se borre manualmenteSe borra al cerrar la pestaña/navegador
ÁmbitoMismo origen (protocolo + dominio + puerto)Mismo origen + misma pestaña
Ventanas/pestañasCompartido entre todas las pestañas del mismo origenAislado por pestaña
DuraciónIlimitada (hasta borrado manual)Solo mientras dure la sesión de la pestaña
// Guardar
localStorage.setItem('nombre', 'Ana');
localStorage.setItem('edad', '25');
// Leer
const nombre = localStorage.getItem('nombre'); // 'Ana'
const edad = localStorage.getItem('edad'); // '25'
const noExiste = localStorage.getItem('fake'); // null
// Eliminar uno
localStorage.removeItem('edad');
// Limpiar todo
localStorage.clear();
// Número de elementos
console.log(localStorage.length); // 0 después de clear

⚠️ Todo se almacena como string. Si guardas un número, lo recuperarás como string.

Como solo acepta strings, hay que serializar con JSON:

const usuario = {
id: 1,
nombre: 'Ana',
preferencias: {
tema: 'oscuro',
idioma: 'es'
}
};
// Guardar (serializar)
localStorage.setItem('usuario', JSON.stringify(usuario));
// Recuperar (deserializar)
const datos = localStorage.getItem('usuario');
if (datos) {
const usuarioRecuperado = JSON.parse(datos);
console.log(usuarioRecuperado.preferencias.tema); // 'oscuro'
}
function guardarStorage(clave, valor) {
try {
localStorage.setItem(clave, JSON.stringify(valor));
return true;
} catch (e) {
console.error('Error al guardar en localStorage:', e);
return false;
}
}
function obtenerStorage(clave) {
try {
const datos = localStorage.getItem(clave);
return datos ? JSON.parse(datos) : null;
} catch (e) {
console.error('Error al leer localStorage:', e);
return null;
}
}

Cuando se modifica localStorage (no sessionStorage) y hay otra pestaña abierta del mismo origen, se dispara el evento storage:

// Escuchar cambios en otras pestañas
window.addEventListener('storage', (event) => {
console.log('Clave modificada:', event.key);
console.log('Valor anterior:', event.oldValue);
console.log('Valor nuevo:', event.newValue);
console.log('URL de origen:', event.url);
console.log('Storage area:', event.storageArea);
});
// Ejemplo: sincronizar tema entre pestañas
window.addEventListener('storage', (e) => {
if (e.key === 'tema') {
document.body.className = e.newValue;
}
});

Idéntica API, pero los datos se borran al cerrar la pestaña:

// Guardar datos temporales (no sobreviven al cierre)
sessionStorage.setItem('carrito', JSON.stringify({
items: ['producto1', 'producto2'],
total: 150
}));
// Útil para datos de una sesión de navegación
sessionStorage.setItem('pasoFormulario', '3');

El límite varía ligeramente entre navegadores (5-10MB). Superarlo lanza una excepción QuotaExceededError:

function esSeguroGuardar(clave, valor) {
try {
const test = JSON.stringify(valor);
localStorage.setItem('__test__', test);
localStorage.removeItem('__test__');
return true;
} catch (e) {
if (e.name === 'QuotaExceededError' || e.code === 22) {
console.warn('Storage lleno');
return false;
}
throw e;
}
}
  • Los datos están en texto plano en el disco del usuario.
  • Cualquier script en la misma página puede acceder a localStorage.
  • No uses localStorage para passwords, tokens de autenticación o datos sensibles.

Las operaciones de localStorage son síncronas y bloquean el hilo principal. Para grandes volúmenes, considera IndexedDB.

// Valores por defecto
const DEFAULTS = {
tema: 'claro',
idioma: 'es',
fontSize: 16
};
function cargarPreferencias() {
const guardadas = localStorage.getItem('preferencias');
return guardadas ? { ...DEFAULTS, ...JSON.parse(guardadas) } : DEFAULTS;
}
function guardarPreferencias(prefs) {
const actuales = cargarPreferencias();
const nuevas = { ...actuales, ...prefs };
localStorage.setItem('preferencias', JSON.stringify(nuevas));
}
// Uso
guardarPreferencias({ tema: 'oscuro' });
const prefs = cargarPreferencias();
console.log(prefs.tema); // 'oscuro'
console.log(prefs.idioma); // 'es' (default)

No existe de forma nativa. Para tests o SSR se usa un polyfill o un mock:

// Mock simple para testing
class MockStorage {
constructor() { this.store = {}; }
getItem(k) { return this.store[k] ?? null; }
setItem(k, v) { this.store[k] = String(v); }
removeItem(k) { delete this.store[k]; }
clear() { this.store = {}; }
get length() { return Object.keys(this.store).length; }
}
global.localStorage = new MockStorage();

🎯 Regla de oro: usa localStorage para preferencias de usuario y datos no sensibles que deben persistir entre sesiones. Usa sessionStorage para datos temporales de una sesión. Nunca guardes contraseñas ni tokens de autenticación.