← Blog
next.jsreactwebengineering

Next.js App Router: cosa uso davvero dopo un anno

27 febbraio 2026

Next.js App Router: cosa uso davvero dopo un anno

L'App Router è diventato il default di Next.js a partire dalla versione 13. Io lo uso in produzione dalla 15, e questo sito gira su Next.js 16. Dopo un anno di utilizzo quotidiano, ho le idee chiare su cosa vale davvero la pena imparare e cosa invece scompare silenziosamente dal codebase dopo una settimana.

Ecco cosa uso davvero.

I layout: la feature che si guadagna il posto

I layout annidati sono il miglioramento più concreto dell'App Router. Il concetto è semplice: ogni layout.tsx avvolge tutte le route sottostanti, e i layout non si rimontano durante la navigazione tra route figlie.

Su questo sito, il [locale]/layout.tsx avvolge ogni pagina con AnimatedBackground e Nav. Prima dell'App Router, mantenere uno shell persistente attorno alle pagine significava mettere tutto in _app.tsx o combattere con lo stato dei componenti. Ora è solo un file nella posizione giusta.

Per app con sezioni autenticate, layout per ruolo, o flussi multi-step, è una svolta. Non rimpiango il vecchio modello.

I Server Component: il cambio di paradigma che conta

I Server Component sono il nucleo concettuale dell'App Router, e ci vuole un po' prima che il modello mentale faccia click. Il punto centrale è questo: i componenti vengono renderizzati sul server per default. Possono essere asincroni. Possono fare fetch dei dati direttamente — niente useEffect, niente stati di caricamento, niente round-trip verso il client.

// Funziona e basta. Nessuna API route necessaria.
export default async function BlogPost({ params }) {
  const post = await getPost(params.slug);
  return <article dangerouslySetInnerHTML={{ __html: post.content }} />;
}

Il blog di questo sito usa questo pattern. Non c'è nessun livello API tra la pagina e il filesystem. Il post viene letto, parsato e renderizzato in un singolo passaggio server-side.

Il confine tra server e client conta però. Una volta aggiunto "use client" a un componente, lui e tutti i suoi figli diventano client component. Sbagliare quel confine — metterlo troppo in alto nell'albero — è l'errore più comune che ho fatto e che ho visto fare agli altri. Parti server-side, e spingi il confine "use client" il più in basso possibile.

generateMetadata: SEO finalmente sensata

Prima dell'App Router, gestire i metadati SEO in Next.js significava usare una libreria di terze parti o inserire manualmente tag <Head> in ogni pagina. generateMetadata sostituisce tutto questo con un export tipizzato e co-locato.

export async function generateMetadata({ params }) {
  const post = await getPost(params.slug);
  return {
    title: post.title,
    description: post.description,
    openGraph: { /* ... */ },
  };
}

È asincrona, quindi puoi fare fetch di dati. È co-locata con la pagina, quindi sai esattamente dove trovare i metadati. Da quando uso questa funzionalità, non ho più toccato next-seo.

Le parti che fanno male

L'App Router non è privo di frizione. Ecco dove ho perso più tempo.

I params asincroni. In Next.js 15+, params e searchParams sono Promise. Bisogna fare await prima di accedere ai valori. Non è ovvio dai messaggi di errore, e mi ha già colto di sorpresa più di una volta:

// Next.js 15+
export default async function Page({ params }) {
  const { slug } = await params; // non dimenticarlo
}

I quirk del middleware. Next.js si aspetta il file di middleware in middleware.ts. Su questo sito si chiama proxy.ts, e funziona grazie a una configurazione specifica — ma se cloni il repo e ti chiedi perché il rilevamento del locale non si attiva, è lì il problema.

La confusione tra rendering statico e dinamico. Una singola chiamata a cookies() o headers() dentro un componente forza l'intera route in rendering dinamico. Questo può eliminare silenziosamente il tuo output statico. L'output di npm run build mostra (statico) vs. ƒ (dinamico) per ogni route — ho imparato a controllarlo.

Cosa evito

Le parallel routes e le intercepting routes. Sono funzionalità potenti, ma non mi sono mai servite. Le parallel routes permettono di renderizzare più segmenti di route indipendenti nello stesso layout. Le intercepting routes permettono di mostrare una route in una modal mantenendo l'URL navigabile. Entrambe sono feature legittime per UI complesse. Per un sito portfolio o un'app SaaS focalizzata, sono quasi certamente eccessive.

ISR con revalidate. La Incremental Static Regeneration esiste ancora nell'App Router tramite export const revalidate = 60. Nel tempo sono passato a scegliere tra rendering completamente statico o completamente dinamico in base alla route. La via di mezzo — dati stale con un timer — introduce una categoria di bug che preferisco non dover debuggare.

Il verdetto onesto

L'App Router vale la pena. Non per una singola feature, ma perché layout, Server Component e generateMetadata insieme eliminano un'enorme quantità di boilerplate che prima era semplicemente il costo di fare Next.js.

La curva di apprendimento è reale e la documentazione, seppur migliorata, sottovaluta ancora quanto debba cambiare il modello mentale. L'intuizione chiave che ho impiegato più tempo a interiorizzare: smetti di pensare prima alle API route e al fetch client-side. Usa un Server Component, fai il fetch dei dati lì, e scendi al client solo quando ti serve davvero interattività.

Quando questo fa click, tutto il resto segue.