# The four cache layers in Next.js

Memoization, Data Cache, Full Route Cache and Router Cache: what each layer keeps, for how long, and how you actually clear it.

> Page: https://ui.eneawork.it/blog/nextjs-caching-quattro-livelli
> Markdown: https://ui.eneawork.it/blog/nextjs-caching-quattro-livelli.md

*2026-11-01*

Next.js non ha una cache: ne ha quattro, con chiavi e durate diverse. Sono la memoizzazione della richiesta, la Data Cache, la Full Route Cache e la Router Cache. Confonderle è la causa più frequente di dati vecchi in pagina.

## Le quattro cache, in ordine

Il build dichiara quale route è statica e quale è dinamica. Quella riga è la prima cosa da leggere quando un dato non si aggiorna: se la route è segnata come statica, il problema non è il browser.

npm run build

## La memoizzazione non è una cache

Due chiamate con gli stessi argomenti nello stesso render producono una richiesta sola. Non sopravvive alla risposta: non c’è niente da invalidare e niente da configurare. Per una query al database si ottiene lo stesso effetto con cache() di React, che deduplica la funzione per il singolo render.

import { cache } from "react"; import { db } from "@/lib/db"; export const getUser = cache(async (id: string) => { return db.user.findUnique({ where: { id } }); });

## Data Cache: la chiave è la richiesta

La Data Cache conserva la risposta di una fetch sul server. La chiave è l’URL più le opzioni, quindi la stessa rotta chiamata con un header diverso non condivide la voce. Con revalidate: 60 la risposta resta valida un minuto; con cache: "no-store" non entra affatto.

const res = await fetch(`https://api.example.com/products/${id}`, { next: { revalidate: 60, tags: [`product-${id}`] }, });

Un tag è la parte che rende la cache manutenibile: invalidi per nome del dato, non per elenco di URL. La chiamata seguente rigenera solo le voci con quel tag.

"use server"; import { revalidateTag } from "next/cache"; export async function updateProduct(id: string, data: ProductInput) { await db.product.update({ where: { id }, data }); revalidateTag(`product-${id}`); }

## Full Route Cache: la pagina intera

Una route senza API dinamiche viene renderizzata al build e servita come HTML più payload RSC. Basta una cookies(), una headers() o una searchParams letta sul server per farla diventare dinamica. Non è un interruttore da mettere a caso: è la conseguenza di quali dati la pagina usa.

## Router Cache: quello che resta nel browser

Il client tiene in memoria i payload delle route già visitate, così il tasto indietro non richiede il server. Dopo una scrittura servono due gesti distinti: revalidatePath invalida la cache del server, router.refresh() quella del browser. Il secondo non aggiorna il database e il primo non tocca la scheda aperta.

## Il sito come caso misurato

Questo blog è il banco di prova: 299 file JSON, letti a ogni richiesta e serviti da una finestra di cache di 5 secondi nel server Express. La finestra corta è una scelta, non un default: con 299 articoli il file system risponde in pochi millisecondi e la cache lunga nasconderebbe una correzione appena pubblicata.

Misurato il 1 novembre 2026 sul repository EneUI: i 299 file in data/blog occupano 3.541.566 byte, con una media di 11.845 byte per file. Metodo: somma di fs.statSync().size sui file *.json con uno script Node; la finestra di 5 secondi è quella impostata in backend/blog.js.

## Dove entrano i componenti del catalogo

Una UI che mostra dati cacheati ha bisogno di stati vuoti, skeleton e filtri che vivono nell’URL. I blocchi dashboard coprono il primo caso, la libreria nuqs il terzo, e le primitive di shadcn il resto. Sono pezzi di interfaccia: la politica di cache resta nella route.

## Dove si sbaglia

## Un limite da dichiarare

Queste cache vivono nel processo Node. Con due istanze, revalidateTag svuota la cache dell’istanza che riceve la chiamata e lascia le altre con la voce vecchia: serve un cache handler condiviso, oppure una scadenza breve che renda l’errore innocuo. Il limite è dell’infrastruttura, non del framework.

Per sapere quale route è statica e quale no, la struttura di un progetto App Router è il punto di partenza; gli errori di cache dopo il deploy sono raccolti in 404 dopo il deploy. Se stai valutando un altro framework, il confronto Remix vs Next.js parte dai modelli di cache.

## FAQ

### Quante cache ha Next.js?

Quattro: memoizzazione della richiesta, Data Cache, Full Route Cache e Router Cache. Ognuna ha una chiave e una durata diverse.

### Come svuoto la cache dopo una modifica?

Con revalidateTag se il dato ha un tag, revalidatePath se serve tutta la route. Per il browser aggiungi router.refresh() dopo la mutazione.

### Perché la mia pagina è sempre dinamica?

Perché legge cookies, headers o searchParams sul server, oppure usa una fetch senza cache. Una sola di queste chiamate toglie la Full Route Cache.

### La Data Cache funziona con un database?

Non direttamente: cachea le fetch. Per le query usa cache() di React nello stesso render, oppure una funzione con la tua cache e i tuoi tag.

### Serve un Redis per la cache?

No con una sola istanza: la cache in memoria del processo basta. Con più istanze serve un handler condiviso, altrimenti l’invalidazione resta locale.
