Solución: localStorage is not defined en Next.js y SSR
localStorage no existe en el servidor — solo en el navegador. Error típico en Next.js, Astro y cualquier framework con SSR. Todas las soluciones para acceder a APIs del browser de forma segura.
¿Por qué ocurre?
Durante el Server-Side Rendering (SSR), el código se ejecuta en Node.js — un entorno sin navegador. localStorage, window, document y navigator no existen en Node.js. Si los usas directamente en el cuerpo del componente o en el servidor, Next.js lanza ReferenceError.
Solución paso a paso
Solución A — Comprueba typeof window antes de acceder:
// ✅ Guarda para cualquier uso de APIs del navegador
const esBrowser = typeof window !== 'undefined';if (esBrowser) {
const valor = localStorage.getItem('tema');
}
Solución B — Solo en useEffect (client-side):
import { useEffect, useState } from 'react';function Componente() {
const [tema, setTema] = useState('claro'); // valor inicial seguro
useEffect(() => {
// useEffect solo se ejecuta en el cliente, nunca en el servidor
const temaGuardado = localStorage.getItem('tema') ?? 'claro';
setTema(temaGuardado);
}, []);
return
...;
}
Solución C — Dynamic import con ssr: false (Next.js):
// Para componentes enteros que dependen de APIs del browser
import dynamic from 'next/dynamic';const ComponenteBrowser = dynamic(
() => import('../components/UsaLocalStorage'),
{ ssr: false } // no renderizar en el servidor
);
Solución D — Hook personalizado seguro:
// hooks/useLocalStorage.ts
import { useState, useEffect } from 'react';export function useLocalStorage(clave: string, valorInicial: T) {
const [valor, setValor] = useState(valorInicial);
useEffect(() => {
try {
const item = localStorage.getItem(clave);
if (item !== null) setValor(JSON.parse(item));
} catch {
// localStorage puede estar bloqueado (modo privado, etc.)
}
}, [clave]);
const guardar = (nuevoValor: T) => {
try {
setValor(nuevoValor);
localStorage.setItem(clave, JSON.stringify(nuevoValor));
} catch {}
};
return [valor, guardar] as const;
}
// Uso
const [tema, setTema] = useLocalStorage('tema', 'claro');
Lo mismo aplica para window, document, navigator:
// ❌ Falla en SSR
const ancho = window.innerWidth;// ✅ Dentro de useEffect o con comprobación
useEffect(() => {
const ancho = window.innerWidth;
}, []);
Cómo evitarlo en el futuro
En Next.js o cualquier framework SSR, trata localStorage y window como APIs asíncronas que solo existen después del mount. Usa siempre useEffect o comprueba `typeof window !== 'undefined'` antes de acceder.
¿Quieres que una IA te ayude? Genera el prompt perfecto para tu error:
Generador de Prompts