Il rilascio di Next.js 15 e 16 segna una svolta fondamentale nel modo in cui approcciamo le prestazioni web. Siamo passati dall'era del caching implicito "magico" a un'era di controllo esplicito e granulare. Con l'introduzione della versione stabile di React Compiler, del Partial Prerendering (PPR) e della rivoluzionaria direttiva use cache, l'App Router è maturato in un motore ad alte prestazioni capace di offrire tempi di caricamento inferiori al secondo anche per applicazioni complesse e ricche di dati.
Ottimizzare un'applicazione Next.js nel 2025 non riguarda più solo la minificazione di JavaScript; si tratta di orchestrare il movimento dei dati tra il server e il client con precisione chirurgica. Questa guida esplora le tecniche avanzate necessarie per padroneggiare le prestazioni nel moderno ecosistema Next.js.
La rivoluzione del caching: dall'implicito all'esplicito
Nelle versioni precedenti dell'App Router, il caching era spesso "implicito". Una singola chiamata a una funzione dinamica come cookies() o headers() poteva inaspettatamente escludere un'intera rotta dal caching. Next.js 16 ha cambiato radicalmente questo approccio con il modello "Cache Components".
La direttiva use cache
La direttiva use cache è l'avanzamento più significativo in Next.js 16. Consente agli sviluppatori di attivare esplicitamente il caching a livello di funzione o di file. Questo pone fine all'imprevedibilità del precedente modello di caching.
- Caching a livello di funzione: Ora puoi avvolgere una logica specifica (come una query al database o una chiamata API esterna) in una funzione async e contrassegnarla con
'use cache';. Next.js memorizzerà il valore di ritorno in base agli argomenti serializzati. - Caching a livello di file: Inserendo
'use cache';all'inizio di un file, viene memorizzata nella cache ogni funzione esportata all'interno di quel file.
// services/products.ts
import { unstable_cacheLife as cacheLife } from 'next/cache';
export async function getProductDetails(productId: string) {
'use cache'; // Attivazione esplicita del caching per questa funzione
cacheLife('minutes'); // Definisce il profilo di scadenza
const res = await fetch(`https://api.acme.com/products/${productId}`);
if (!res.ok) throw new Error('Failed to fetch product');
return res.json();
}API per il controllo granulare della cache
Per supportare questo modello esplicito, Next.js ha introdotto diverse nuove API per la gestione della cache:
cacheLife: Sostituisce le vecchie costanti direvalidate. Accetta profili come'minutes','hours', o'days', rendendo più semplice la gestione del TTL (Time To Live) in diversi ambienti.cacheTagerevalidateTag: Rimangono lo standard di riferimento per l'invalidazione on-demand. Taggando un segmento memorizzato nella cache, puoi eliminarlo immediatamente quando i dati cambiano (ad esempio, dopo un webhook del CMS).

Padroneggiare i pattern di rendering: PPR e Streaming
L'obiettivo dell'ottimizzazione delle prestazioni è ridurre il Time to First Byte (TTFB) e l'Interaction to Next Paint (INP). Next.js 16 raggiunge questo obiettivo attraverso la stabilizzazione del Partial Prerendering (PPR).
Partial Prerendering (PPR) stabile
Il PPR consente di combinare rendering statico e dinamico sulla stessa pagina senza sovraccarico di configurazione. Quando un utente richiede una pagina, Next.js serve immediatamente una shell HTML statica (contenente il layout, la navigazione e i contenuti statici). Gli "spazi dinamici" — parti della pagina che richiedono dati specifici dell'utente — sono avvolti in confini <Suspense> e vengono trasmessi in streaming man mano che vengono risolti.
Per abilitare il PPR, configuralo nel tuo next.config.js:
// next.config.js
const nextConfig = {
experimental: {
ppr: 'incremental', // Adotta gradualmente il PPR nelle tue rotte
},
};
module.exports = nextConfig;Il ruolo di React 19 e del React Compiler
Next.js 16 sfrutta la versione stabile di React Compiler. In precedenza, gli sviluppatori passavano molto tempo a ottimizzare manualmente i componenti con useMemo, useCallback e React.memo per prevenire re-render non necessari. Il React Compiler automatizza questo processo analizzando il codice e applicando la memoizzazione dove offre il maggior beneficio.
Questo si traduce in:
- Minore lavoro sul Main Thread: I componenti si ri-renderizzano solo quando le loro effettive dipendenze di dati cambiano.
- INP migliorato: Riducendo il lavoro che React svolge durante gli aggiornamenti, il browser rimane reattivo agli input dell'utente.
Strategie di recupero dati ad alte prestazioni
Il recupero dei dati (data fetching) è spesso il principale collo di bottiglia nelle applicazioni web. Nell'App Router, dobbiamo allontanarci dai "waterfall" sequenziali e muoverci verso l'esecuzione parallela e lo streaming.
Eliminare i waterfall di richieste
Un errore comune è attendere più chiamate fetch una dopo l'altra. Questo costringe la seconda richiesta ad aspettare la fine della prima, raddoppiando la latenza.
L'Anti-Pattern (Lento):
const user = await getUser(); // Impiega 500ms
const posts = await getPosts(user.id); // Impiega 500ms (Totale: 1000ms)Il Pattern Ottimizzato (Veloce):
// Avvia entrambe le richieste in parallelo
const userPromise = getUser();
const postsPromise = getPosts();
// Attendi la risoluzione di entrambe
const [user, posts] = await Promise.all([userPromise, postsPromise]);Sfruttare i Server Components per l'ottimizzazione "Leaf"
Per ridurre al minimo il bundle JavaScript inviato al client, dovresti mantenere i tuoi "Client Components" alle estremità (foglie) del tuo albero dei componenti. Se contrassegni un layout di alto livello come "use client", ogni componente importato in quel layout diventa parte del bundle client.
Invece, passa i Server Components come children o props ai Client Components per mantenere il vantaggio del "Server-First".
// Errato: L'intera pagina è un Client Component
"use client"
export default function Dashboard({ data }) {
return <Sidebar>{/* logica complessa */}</Sidebar>;
}
// Corretto: Solo il toggle interattivo è un Client Component
export default function DashboardPage() {
return (
<Sidebar>
<Suspense fallback={<Skeleton />}>
<DataList /> {/* Server Component */}
</Suspense>
<InteractiveToggle /> {/* Client Component */}
</Sidebar>
);
}
Ottimizzazione degli Asset e il passaggio a Turbopack
Gli asset — immagini, font e script — rappresentano spesso la parte più consistente del peso di una pagina. Next.js fornisce primitive integrate per gestirli automaticamente.
Ottimizzazione delle immagini con next/image
Il componente next/image è molto più di un semplice tag <img>. Nel 2025, è essenziale usare l'attributo priority per gli elementi Largest Contentful Paint (LCP) e l'attributo sizes per evitare che il browser scarichi immagini troppo grandi per il viewport.
<Image
src="/hero.jpg"
alt="Immagine Hero"
width={1200}
height={600}
priority // Essenziale per LCP
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>Ottimizzazione dei font e Zero Layout Shift
L'uso di next/font ti consente di ospitare i font localmente e gestisce automaticamente la proprietà font-display. Questo elimina il Layout Shift (CLS) causato dal caricamento dei font dopo il rendering iniziale. Utilizzando le variabili CSS con next/font, puoi assicurarti che la tua tipografia sia pronta nel momento in cui l'HTML viene analizzato.
Turbopack: Il nuovo standard
Con Turbopack ora bundler predefinito in Next.js 16, i tempi di build e le velocità di Fast Refresh sono migliorati drasticamente. Turbopack utilizza un motore di calcolo incrementale scritto in Rust, che ricompila solo il codice esatto che è cambiato. Per applicazioni su larga scala, questo può ridurre i tempi di build di produzione fino all'80%.
Monitoraggio e validazione nel mondo reale
L'ottimizzazione delle prestazioni non è un compito da "imposta e dimentica". Devi convalidare i tuoi miglioramenti utilizzando il Real User Monitoring (RUM).
- Vercel Speed Insights: Questo strumento fornisce una dashboard in tempo reale dei Core Web Vitals (LCP, INP, CLS) della tua applicazione basata su dati utente reali.
- Sentry e OpenTelemetry: Per approfondimenti maggiori, specialmente nei Server Components e nelle rotte API, usa il tracciamento basato su OpenTelemetry. Questo ti consente di vedere esattamente quale query al database o chiamata API esterna sta rallentando il tuo Server Side Rendering (SSR).
- Zod per la sicurezza a runtime: Anche se non è uno strumento diretto per la "velocità", l'uso di Zod per validare le risposte API assicura che l'applicazione non si blocchi o si carichi all'infinito a causa di formati dati imprevisti, il che può portare a una scarsa percezione delle prestazioni.

Domande Frequenti
Come posso ottimizzare le prestazioni in Next.js App Router?
L'ottimizzazione nell'App Router si concentra sull'uso dei Server Components per impostazione predefinita per ridurre il JavaScript lato client e sull'implementazione del Partial Prerendering (PPR) per caricamenti iniziali veloci. Inoltre, sfrutta la direttiva use cache per un caching granulare dei dati e assicurati di usare next/image e next/font per l'ottimizzazione degli asset.
Next.js App Router è più veloce del Pages Router?
L'App Router è generalmente più veloce perché abilita i React Server Components (RSC), che riducono significativamente la quantità di JavaScript inviata al browser. Supporta anche funzionalità avanzate come lo Streaming e il Partial Prerendering che non sono disponibili nel Pages Router, portando a migliori Core Web Vitals.
Come ridurre la dimensione del bundle JavaScript in Next.js?
Per ridurre la dimensione del bundle, sposta l'interattività verso le "foglie" dell'albero dei componenti e usa importazioni dinamiche (next/dynamic) per librerie di terze parti pesanti. Evita di posizionare la direttiva "use client" al livello superiore dei tuoi layout, poiché questo forza tutti i componenti figli nel bundle lato client.
Come funziona il caching nel Next.js App Router?
In Next.js 16, il caching è esplicito tramite la direttiva use cache, consentendoti di memorizzare funzioni o file con profili TTL specifici utilizzando cacheLife. Utilizza inoltre un sistema di caching a più livelli, inclusi Request Memoization, Data Cache e Full Route Cache, per ridurre al minimo le elaborazioni ridondanti.
Quali sono le best practice per il recupero dei dati in Next.js?
Recupera sempre i dati sul server utilizzando i Server Components per mantenere la logica vicina alla sorgente dati e ridurre il sovraccarico lato client. Usa il recupero parallelo con Promise.all per evitare waterfall e avvolgi i recuperi dati lenti in confini <Suspense> per abilitare lo streaming per una migliore esperienza utente.
Conclusione
Ottimizzare le prestazioni nel Next.js App Router è un percorso verso il controllo esplicito. Abbracciando la direttiva use cache, sfruttando il Partial Prerendering e permettendo al React Compiler di gestire le ottimizzazioni di basso livello, puoi costruire applicazioni che non sono solo veloci, ma anche resilienti e mantenibili.
Guardando al futuro del web nel 2025 e 2026, l'attenzione si è spostata da "quanto possiamo inviare al client" a "di quanto abbiamo effettivamente bisogno". Seguendo queste best practice, assicurerai che le tue applicazioni Next.js rimangano all'avanguardia in termini di velocità ed esperienza utente.