localStorage guarda datos en el navegador del usuario y los conserva aunque cierre la pestaña o apague el equipo. Es lo más sencillo para recordar preferencias, como el tema oscuro o el último filtro elegido.
También te puede interesar
Guardar, leer y borrar
Para probarlo, guarda el código en un archivo .html, ábrelo en el navegador y abre la consola con F12 (en Mac, Cmd+Opción+J). Todos los ejemplos de esta página son un único archivo, sin nada más que instalar.
<!doctype html>
<html lang="es">
<head><meta charset="utf-8"><title>localStorage</title></head>
<body>
<script type="module">
localStorage.clear();
// Guardar y leer
localStorage.setItem("tema", "oscuro");
console.log(localStorage.getItem("tema"));
console.log(localStorage.getItem("no-existe"));
// Solo guarda cadenas
localStorage.setItem("visitas", 5);
localStorage.setItem("usuario", { nombre: "Ana" });
console.log(typeof localStorage.getItem("visitas"), localStorage.getItem("visitas") + 1);
console.log(localStorage.getItem("usuario"));
// Con JSON sí
const prefs = { tema: "oscuro", tamano: 18, avisos: ["correo"] };
localStorage.setItem("prefs", JSON.stringify(prefs));
const leidas = JSON.parse(localStorage.getItem("prefs"));
console.log(leidas.tamano + 1, leidas.avisos[0]);
// Recorrer, borrar una, borrar todo
console.log(localStorage.length, Object.keys(localStorage).sort().join(", "));
localStorage.removeItem("usuario");
console.log(localStorage.length);
</script>
</body>
</html>consolaoscuro null string 51 [object Object] 19 correo 4 prefs, tema, usuario, visitas 3
La API son cuatro métodos: setItem(clave, valor), getItem(clave), removeItem(clave) y clear(). Si la clave no existe, getItem devuelve null, no undefined.
Solo guarda texto
Es la sorpresa de las líneas tres y cuatro. setItem("visitas", 5) guarda la cadena "5", y al leerla y sumarle 1 sale "51", porque se pegan dos textos. Un objeto es peor: se guarda como "[object Object]" y el contenido se pierde para siempre. Para guardar números, listas u objetos hay que pasarlos por JSON.stringify al guardar y por JSON.parse al leer, como hace el ejemplo con prefs.
Dos funciones que conviene tener siempre
Leer puede fallar si alguien guardó algo que no es JSON, y guardar puede fallar si se llena el espacio o si el navegador bloquea el almacenamiento. Estas dos funciones lo resuelven de una vez:
<!doctype html>
<html lang="es">
<head><meta charset="utf-8"><title>localStorage con valores por omisión</title></head>
<body>
<script type="module">
function leer(clave, porOmision) {
try {
const texto = localStorage.getItem(clave);
return texto === null ? porOmision : JSON.parse(texto);
} catch {
return porOmision;
}
}
function guardar(clave, valor) {
try {
localStorage.setItem(clave, JSON.stringify(valor));
return true;
} catch (err) {
console.log("no se pudo guardar:", err.name);
return false;
}
}
localStorage.clear();
console.log(JSON.stringify(leer("prefs", { tema: "claro" })));
guardar("prefs", { tema: "oscuro" });
console.log(JSON.stringify(leer("prefs", { tema: "claro" })));
localStorage.setItem("roto", "{esto no es json");
console.log(JSON.stringify(leer("roto", [])));
console.log(guardar("enorme", "x".repeat(6 * 1024 * 1024)));
</script>
</body>
</html>consola{"tema":"claro"}
{"tema":"oscuro"}
[]
no se pudo guardar: QuotaExceededError
falseEl último intento guarda 6 MiB de texto, más de lo que cabe, y el navegador lanza un QuotaExceededError. Medimos el límite en Chromium: caben unos 5,242,000 caracteres por sitio, sumando todas las claves. Firefox y Safari tienen límites parecidos.
Enterarse de los cambios en otra pestaña
<!doctype html>
<html lang="es">
<head><meta charset="utf-8"><title>Evento storage</title></head>
<body>
<script type="module">
window.addEventListener("storage", (e) => {
console.log(`otra pestaña cambió «${e.key}»: ${e.oldValue} -> ${e.newValue}`);
});
</script>
</body>
</html>Con esta página abierta en dos pestañas, cambiamos el tema desde la segunda: primero «claro», luego «oscuro», y después lo borramos. En la consola de la primera aparece:
consolaotra pestaña cambió «tema»: null -> claro otra pestaña cambió «tema»: claro -> oscuro otra pestaña cambió «tema»: oscuro -> null
El evento storage salta en las demás pestañas del mismo sitio, nunca en la que hizo el cambio. Sirve, por ejemplo, para que todas cambien a la vez cuando el usuario activa el tema oscuro en una.
Cuál usar
| Lo que necesitas | Lo que conviene |
|---|---|
| Preferencias pequeñas que duren | localStorage |
| Algo que solo importa mientras la pestaña esté abierta | sessionStorage, con la misma API |
| Que el servidor lo reciba en cada petición | Una cookie |
| Muchos datos, archivos o búsquedas | IndexedDB |
localStorage. Cualquier script que se ejecute en tu página puede leerlo, incluido uno inyectado con un ataque XSS. Y el usuario puede borrarlo, o puede que el navegador no lo conserve en una ventana privada: trátalo como una comodidad, no como un sitio fiable para datos importantes.Cada página de esta sección se abrió en Chromium 131, el motor de Chrome, controlado con Playwright, antes de publicarla; lo que aparece como consola es lo que imprimió de verdad. Documentación oficial: localStorage en MDN.