# window is not defined in Next.js: dove nasce e come si corregge

Il server non ha `window`. L'errore compare quando un componente o un modulo legge API del browser durante il render o l'import. Tre correzioni, in ordine di costo.

> Pagina: https://ui.eneawork.it/blog/finestra-non-definita-nextjs
> Markdown: https://ui.eneawork.it/blog/finestra-non-definita-nextjs.md

*2026-11-01*

Risposta breve: durante il render sul server window non esiste. L'errore compare ogni volta che un modulo legge window all'import o un componente lo legge nel corpo del render. Sposta l'accesso in useEffect, oppure importa il componente solo sul client.

La domanda «Window is not defined in Next.js React app» vale 331 voti su Stack Overflow (letto il 31 ottobre 2026 con la Stack Exchange API): fonte. Il catalogo EneUI misura 111.985 componenti, 1.556 blocchi, 12.808 icone da 1.472 librerie, letti da /api/stats il 1 novembre 2026. Ogni comando qui sotto è eseguibile in locale: nessun passaggio richiede un account.

## Il messaggio esatto

ReferenceError: window is not defined at Object. (/app/lib/analytics.js:3:12) at Module._compile (node:internal/modules/cjs/loader:1358:14)

La riga indicata è quasi sempre al livello superiore del file, non dentro una funzione. È il dettaglio che distingue un errore di rendering da un errore di import.

## Perché succede

Next.js esegue il codice dei Server Component e il prerender delle pagine in Node. Node non ha window, document, localStorage né navigator. Un modulo che inizializza un client analytics al momento dell'import viene eseguito anche in quel contesto.

## La correzione, tre livelli

Se il valore serve solo dopo l'interazione, useEffect è sufficiente: gira solo nel browser e non partecipa al prerender.

"use client"; import { useEffect, useState } from "react"; export function Width() { const [width, setWidth] = useState(0); useEffect(() => { const onResize = () => setWidth(window.innerWidth); onResize(); window.addEventListener("resize", onResize); return () => window.removeEventListener("resize", onResize); }, []); return {width || "—"}; }

Se il componente intero dipende dal browser, una mappa, un editor, una canvas, caricalo senza SSR. In App Router ssr: false è consentito solo dentro un Client Component.

"use client"; import dynamic from "next/dynamic"; const Editor = dynamic(() => import("./editor"), { ssr: false }); export function EditorShell() { return ; }

Se l'errore arriva da una libreria, la via più pulita è una guardia esplicita più un import dinamico: il modulo non viene valutato finché non serve.

## Quando la correzione non funziona

typeof window !== "undefined" evita il crash ma non è una soluzione: il valore calcolato sul server resta diverso da quello del client, e ottieni un hydration mismatch al posto del ReferenceError. Allo stesso modo, spostare l'accesso in una funzione che viene chiamata durante il render non cambia nulla: conta quando viene eseguita, non dove è scritta.

## Come prevenirlo

## Dove continuare

Per partire da codice già eseguibile: componenti React, una dashboard con shell e tutti i blocchi con preview. Le guide collegate sono App Router, struttura e confini client/server e quanto pesa una libreria UI; il confronto utile è copy-paste o headless.

## FAQ

### Perché l'errore appare solo al build?

Durante `next build` le pagine vengono prerenderizzate: il codice che legge `window` al livello del modulo viene eseguito in Node.

### `typeof window !== "undefined"` basta?

Evita il crash, ma non è una correzione: il valore calcolato sul server resta diverso da quello del client e può produrre un hydration mismatch.

### Posso usare `useEffect` per leggere `window`?

Sì, gli effetti girano solo nel browser. Inizializza lo stato con un valore neutro e aggiornalo nell'effetto.

### Perché `ssr: false` dà errore in un Server Component?

Next.js 15 non permette `ssr: false` in un Server Component. Metti `"use client"` nel file che chiama `dynamic`, oppure avvolgi il componente in un client wrapper.

### Vale anche per `document` e `localStorage`?

Sì. Tutte le API del browser mancano in Node: la regola è la stessa, cambia solo il nome.
