f in x
> cd .. / HUB_EDITORIALE > Visualizza in Inglese
Sviluppo di siti web

Data Fetching in Next.js — Cache, Revalidation e ISR per Applicazioni che non Rallentano

[2026-06-23] Author: Ing. Calogero Bono

Il tuo sito Next.js vola in sviluppo, ma in produzione ogni pagina impiega secondi perché i dati vengono recuperati da capo ad ogni richiesta. Oppure hai dati che cambiano ogni ora e non sai se metterli statici o dinamici, rischiando di servire contenuti vecchi o di perdere performance. Conosciamo bene questo scenario: lo vediamo in molti progetti che ci arrivano, dove il caching è trascurato e il Time to First Byte (TTFB) sale senza motivo.

Next.js mette a disposizione un sistema di caching a più livelli (Data Cache, Full Route Cache, Router Cache) che, se usato correttamente, permette di avere pagine velocissime senza rinunciare a dati freschi. In questa guida vediamo come controllare il caching di fetch, come usare la revalidation a tempo e on demand, e come sfruttare l’Incremental Static Regeneration (ISR) per combinare staticità e aggiornamento automatico. Niente teoria accademica: solo ciò che serve per fare la scelta giusta nel tuo progetto.

Come funziona il data fetching caching predefinito in Next.js?

Per capire cosa modificare, prima bisogna sapere cosa fa Next.js di default quando usi fetch in un Server Component. Senza specificare opzioni, Next.js adotta il comportamento statico: i risultati di fetch vengono memorizzati nella Data Cache persistente su disco e la pagina generata viene cacheata nella Full Route Cache (statica). Questo significa che, a build, la pagina viene generata una volta e servita a tutti gli utenti senza eseguire di nuovo le fetch. Perfetto per dati che cambiano raramente (es. pagina “Chi siamo”, blog post).

Attenzione però: se i dati cambiano spesso e non gestisci la cache, servirai contenuti obsoleti. Noi di Meteora Web abbiamo visto clienti con un catalogo prodotti che si bloccavano su dati vecchi di giorni perché non avevano configurato la revalidation.

Sponsored Protocol

Cache a tre livelli: cosa conta davvero

Non serve memorizzare tutti i dettagli, ma è utile sapere che:

  • Data Cache: dove finiscono i risultati di fetch. È persistente e condivisa tra le richieste.
  • Full Route Cache: la pagina HTML completa, generata dal Server Component. Se attiva, la risposta è immediata.
  • Router Cache: nel browser, per navigazioni lato client.

Quando parliamo di data fetching caching, interveniamo principalmente sulla Data Cache e sulla Full Route Cache attraverso le opzioni di fetch e le API di Next.js.

Come e quando usare la revalidation periodica con fetch?

La revalidation periodica (o time-based revalidation) è il metodo più semplice per mantenere i dati freschi senza rinunciare ai benefici del caching. Si aggiunge l’opzione next: { revalidate: secondi } alla chiamata fetch.

Esempio: recuperiamo un elenco di post aggiornato ogni 60 secondi.

// app/posts/page.tsx
export default async function PostsPage() {
  const res = await fetch('https://api.example.com/posts', {
    next: { revalidate: 60 }
  });
  const posts = await res.json();

  return (
    
    {posts.map(post =>
  • {post.title}
  • )}
); }

Cosa succede esattamente?

  1. Alla prima richiesta dopo il build, Next.js esegue la fetch, salva il risultato nella Data Cache e restituisce la pagina.
  2. Per i successivi 60 secondi, ogni richiesta riceve la pagina cacheata (senza eseguire la fetch).
  3. Dopo 60 secondi, la prossima richiesta innesca una revalidazione in background: Next.js serve ancora la vecchia pagina, ma avvia una nuova fetch. Se la fetch ha successo, la cache viene aggiornata per le richieste successive; se fallisce, la vecchia pagina rimane valida.

Questo meccanismo è ideale per dati che cambiano con frequenza prevedibile (es. feed di news, prezzi aggiornati ogni ora). Noi lo usiamo spesso nei progetti WooCommerce per sincronizzare il catalogo senza appesantire il server a ogni visita.

Sponsored Protocol

Revalidation on demand con revalidateTag e revalidatePath

Quando i dati cambiano in momenti imprevedibili (es. un utente modifica un post, arriva un nuovo ordine), la revalidation periodica non basta: si rischia di servire dati vecchi fino al prossimo intervallo. Next.js offre due funzioni da chiamare lato server (server actions, webhook, API route):

  • revalidatePath('/percorso') — invalida la cache di una specifica route (o di tutte le route che contengono quel percorso).
  • revalidateTag('tag') — invalida tutte le fetch che hanno quel tag, indipendentemente dalla route.

Per usare i tag, devi aggiungerli alla fetch:

// durante la fetch
const res = await fetch('https://api.example.com/products', {
  next: { tags: ['products'] }
});

// dopo un aggiornamento (es. in una server action)
import { revalidateTag } from 'next/cache';

export async function updateProduct(id: string, data: any) {
  // ... aggiorna il database
  revalidateTag('products');
}

Quando preferire i tag? Se hai più pagine che mostrano gli stessi dati (es. lista prodotti, dettaglio prodotto, scheda correlata), un unico tag invalida tutte le cache interessate. revalidatePath invece è più granulare e utile per invalidare una singola pagina (es. la home dopo aver pubblicato un nuovo articolo).

Come funziona l’ISR (Incremental Static Regeneration) con Next.js?

L’ISR è una tecnica che unisce la generazione statica (SSG) con la possibilità di aggiornare le pagine dopo il build, senza dover ricostruire l’intero sito. In Next.js App Router, l’ISR si ottiene combinando generateStaticParams con l’opzione revalidate nel fetch o nella pagina stessa (tramite export const revalidate = 60).

Sponsored Protocol

Immagina un blog con centinaia di articoli. Con ISR puoi generare staticamente le pagine più visitate al build, e poi aggiornarle progressivamente man mano che vengono richieste pagine nuove o modificate.

// app/blog/[slug]/page.tsx

export async function generateStaticParams() {
  const posts = await fetch('https://api.example.com/posts').then(r => r.json());
  return posts.map(post => ({ slug: post.slug }));
}

export default async function BlogPost({ params }: { params: { slug: string } }) {
  const res = await fetch(`https://api.example.com/posts/${params.slug}`, {
    next: { revalidate: 300 } // 5 minuti
  });
  const post = await res.json();

  return 
{post.content}
; }

Come funziona l’ISR passo dopo passo:

  1. Al next build, vengono generate staticamente solo le pagine elencate in generateStaticParams.
  2. Alla prima richiesta di una pagina non pre-generata (slug non presente nel parametro), Next.js la genera dinamicamente e la cachea nella Full Route Cache. Questa è la lazy generation tipica dell’ISR.
  3. Ogni pagina, una volta cacheata, ha un TTL (time-to-live) definito da revalidate. Dopo quel tempo, la prossima richiesta scatena una revalidazione in background (come nella revalidation periodica).
  4. Se la fetch fallisce durante la revalidazione, la vecchia pagina resta servita (stale-while-revalidate).

Attenzione a non confondere ISR con revalidation di fetch: in questo esempio, revalidate: 300 sulla fetch fa sì che la Data Cache scada ogni 5 minuti. La pagina (Full Route Cache) segue lo stesso TTL, ma potrebbe essere rigenerata prima se la Data Cache è già stata invalidata. Nella pratica, per l’ISR è sufficiente impostare revalidate a livello di fetch; Next.js si occupa di rigenerare la pagina quando necessario.

Sponsored Protocol

ISR con revalidatePath per aggiornamenti immediati

L’ISR periodico non è abbastanza quando un contenuto viene modificato da un’azione utente (es. un editor pubblica un nuovo post). In questi casi, combinalo con revalidatePath o revalidateTag dopo il salvataggio. Esempio tipico: un webhook da un CMS headless:

// app/api/revalidate/route.ts
import { revalidatePath } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const secret = request.headers.get('x-secret');
  if (secret !== process.env.REVALIDATION_SECRET) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }
  
  const { slug } = await request.json();
  revalidatePath(`/blog/${slug}`);
  return NextResponse.json({ revalidated: true });
}

Con questo approccio, appena il CMS notifica un aggiornamento, Next.js invalida la cache di quella specifica pagina. Nessun tempo di attesa, nessun build completo.

Quale strategia di caching scegliere per dati dinamici e statici?

Non esiste una risposta unica. Noi, di Meteora Web, consigliamo di partire da questa matrice decisionale:

  • Dati che cambiano meno di una volta al giorno: usa il caching predefinito (senza revalidate) o next: { revalidate: 86400 }. Hai pagine statiche al build, velocissime. Se pubblichi un aggiornamento, usa il webhook per revalidare.
  • Dati che cambiano ogni pochi minuti (es. prezzi, disponibilità): revalidation periodica con revalidate: 60 o 300. Accetta un lieve ritardo per dati non critici.
  • Dati in tempo reale (chat, notifiche, dashboard): evita la Data Cache del server. Usa fetch(url, { cache: 'no-store' }) o fetch(url, { next: { revalidate: 0 } }). Le pagine saranno dinamiche e sempre aggiornate, ma perderai i benefici del caching lato server.
  • Pagine con molti contenuti statici e alcune parti dinamiche: usa Streaming con Suspense e React Server Components. Le parti statiche vengono cacheate, quelle dinamiche vengono fetchate senza bloccare il rendering della pagina. Next.js lo supporta nativamente con loading.js e streaming.

Un errore comune che correggiamo spesso nei progetti ereditati: usare cache: 'no-store' su tutte le fetch per paura di dati obsoleti, perdendo completamente il caching. Se hai pochi dati critici, isolali in componenti separati e lascia il resto statico.

Sponsored Protocol

Cosa fare adesso

  1. Analizza la frequenza di aggiornamento dei dati della tua applicazione. Dividi le pagine in tre categorie: statiche, semi-dinamiche, dinamiche.
  2. Per ogni fetch, scegli una strategia: revalidate: n per dati che cambiano con regolarità, tags + revalidation on demand per dati modificati da azioni utente, cache: 'no-store' solo dove serve.
  3. Implementa almeno un endpoint di revalidation (webhook o server action) per aggiornare la cache senza dover fare un nuovo build.
  4. Verifica con next build che le pagine vengano generate staticamente come previsto, e usa next dev con NODE_ENV=production per testare la cache.
  5. Monitora il TTFB su pagine cacheate vs non cacheate. Se vedi tempi superiori a 200ms su pagine statiche, c’è qualcosa che non va (forse una fetch non cacheata).

Per approfondire l’ecosistema Next.js, leggi la nostra guida principale: Next.js App Router — Server Components, Data Fetching e Full-Stack per Applicazioni che Funzionano.

Se hai domande su casi specifici (e-commerce, dashboard, blog con milioni di pagine), contattaci. Ogni giorno lavoriamo su questi aspetti con aziende italiane che vogliono performance vere, non solo belle parole.

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Ingegnere Informatico, co-fondatore di Meteora Web. Esperto in architetture software, sicurezza informatica e sviluppo sistemi scalabili.
[ Read Full Dossier ]

> METEORA_WEB // WEB AGENCY

Costruiamo la presenza digitale che la tua azienda merita.

Siti web, social, pubblicità online, e-commerce e hosting performante: ingegnerizzati con metodo da ingegneri informatici a Sciacca, per tutta Italia.

> MW_JOURNAL

> READ_ALL()