Se hai iniziato da poco a usare Next.js 13+, probabilmente hai aperto un progetto e hai pensato:
“Perché questa struttura di cartelle sembra così... diversa?”
Con l’App Router, la directory app/ è diventata il cuore di ogni progetto Next.js moderno. Ma per molti sviluppatori—soprattutto quelli che arrivano dal vecchio pages/ router—la struttura delle cartelle può risultare inizialmente confusa.
Sistemiamo le cose.
TL;DR
- La directory
app/di Next.js introduce un’architettura basata su file che controlla routing, layout e comportamento del rendering.- File speciali come
page.tsx,layout.tsx,loading.tsx,error.tsxenot-found.tsxdefiniscono come si comportano le route.- Una struttura pulita con route groups e dynamic routes rende le app Next.js scalabili e manutenibili.
Table of Contents
- Perché la directory app/ è importante
- Il concetto base: File-Based Routing
- I file essenziali dentro app/
- Layouts: l’arma segreta
- Loading ed Error States
- Error Boundaries: una limitazione importante
- Gestire le 404 con not-found.tsx
- Dynamic Routes
- Route Groups
- Una struttura reale
- Errori comuni
- Considerazioni finali
Perché la directory app/ è importante
Quando Next.js ha introdotto l’App Router, non era solo una nuova cartella.
Era un cambio di paradigma.
Invece di spargere la logica in più livelli, la directory app/ organizza l’app attorno a route e segmenti UI.
Pensala così:
URL → Cartella → UI
Questo approccio rende le applicazioni grandi molto più facili da capire.
Invece di chiederti:
“Dov’è il componente per questa pagina?”
Vai direttamente nella cartella che corrisponde alla route.
Il concetto base: File-Based Routing
Nel app/ directory il routing è semplice.
Le cartelle definiscono le route.
Esempio:
app/
page.tsx
about/
page.tsx
dashboard/
page.tsx
Questo genera:
/ → page.tsx
/about → about/page.tsx
/dashboard → dashboard/page.tsx
Una pagina base:
export default function Page() {
return <h1>Hello Next.js</h1>
}
Zero configurazione di routing.
I file essenziali dentro app/
Next.js usa nomi di file speciali per definire il comportamento.
page.tsx
Definisce la UI della route.
export default function Page() {
return <div>Dashboard</div>
}
Ogni route accessibile deve avere un page.tsx.
layout.tsx
I layout wrappano più pagine e persistono durante la navigazione.
app/
layout.tsx
dashboard/
layout.tsx
page.tsx
Esempio:
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<main>
<nav>Navigation</nav>
{children}
</main>
)
}
I layout non vengono ri-renderizzati durante la navigazione, il che li rende perfetti per:
- navbar
- sidebar
- UI condivisa
Layouts: l’arma segreta
Uno dei punti più forti dell’App Router sono i layout annidati.
app/
layout.tsx
dashboard/
layout.tsx
analytics/
page.tsx
Rendering:
Root Layout
↓
Dashboard Layout
↓
Analytics Page
Questo permette UI complesse senza duplicare codice.
Loading ed Error States
Next.js supporta stati UI a livello di route.
loading.tsx
Mostrato durante il caricamento.
export default function Loading() {
return <p>Loading...</p>
}
error.tsx
Gestisce errori nel segmento.
"use client" // Gli error boundaries devono essere componenti client
export default function Error({ error }: { error:Error }) {
return <p>Something went wrong</p>
}
Error Boundaries: una limitazione importante
Il file error.tsx funziona come un gestore di errori React per un segmento di percorso.
Tuttavia, esiste un limite importante che molti sviluppatori trascurano.
I gestori di errori non intercettano gli errori all'interno dei gestori di eventi.
Cattura solo errori durante:
- rendering
- server components
- data fetching
Esempio:
"use client"
export default function Error({
error,
reset,
}: {
error:Error
reset: () => void
}) {
return (
<div>
<h2>C'è stato un errore.</h2>
<button onClick={() => reset()}>
Riprova
</button>
</div>
)
}
Gli errori generati all'interno dei gestori di eventi devono comunque essere gestiti manualmente. Ad esempio:
"use client"
export default function Button() {
const handleClick = () => {
try {
throw new Error("Boom");
} catch (err) {
console.error(err);
}
}
return <button onClick={handleClick}>Click</button>
}
Considera error.tsx come una rete di sicurezza per l'interfaccia utente, non come un sistema completo di gestione degli errori.
Gestire le 404 con not-found.tsx
Next.js semplifica le 404.
export default function NotFound() {
return (
<h2>Pagina non trovata</h2>
)
}
Trigger:
import {notFound} from "next/navigation"
if (!post) {
notFound()
}
Supporta livelli multipli:
app/
not-found.tsx
dashboard/
not-found.tsx
Viene usato quello più vicino.
Dynamic Routes
I dynamic routes usano le parentesi quadre.
Ad esempio:
app/
blog/
[slug]/
page.tsx
URL generati:
/blog/my-first-post
/blog/nextjs-routing
/blog/react-performance
Esempio di implementazione:
export default function BlogPost({
params
}: {
params: { slug: string }
}) {
return <h1>{params.slug}</h1>
}
È possibile combinarlo anche con la generazione statica.
Segmenti multipli
Esempio:
app/
shop/
[category]/
[product]/
page.tsx
Esempi di route generate:
/shop/laptops/macbook-pro
/shop/phones/iphone-15
Esempio di codice:
export default function ProductPage({
params
}: {
params: {
category:string
product:string
}
}) {
return (
<div>
<h1>{params.product}</h1>
<p>Category: {params.category}</p>
</div>
)
}
Route Catch-all
A volte servono percorsi flessibili.
Next.js supporta i segmenti catch-all.
[...slug]
Esempio:
app/
docs/
[...slug]/
page.tsx
URL supportati:
/docs
/docs/getting-started
/docs/guides/routing
/docs/api/config
Implementazione:
export default function DocsPage({
params
}: {
params: { slug: string[] }
}) {
return <div>{params.slug?.join("/")}</div>
}
Optional route catch-all
È la versione opzionale:
[[...slug]]
Questo supporta entrambi:
/docs
/docs/routing
/docs/config/api
Tutto gestito dalla stessa pagina.
Comprendere i Route Groups
I Route Groups aiutano a organizzare il codice senza influire sugli URL.
Usano le parentesi tonde:
app/
(marketing)/
page.tsx
about/
page.tsx
(dashboard)/
dashboard/
page.tsx
URL generati:
/
/about
/dashboard
Non appaiono nelle URL e sono perfetti per separare diverse sezioni dell'app così da avere:
- layout differenti
- provider differenti
- strutture UI differenti
Un esempio pratico
app/
layout.tsx
page.tsx
(marketing)/
page.tsx
about/
page.tsx
(dashboard)/
dashboard/
layout.tsx
page.tsx
analytics/
page.tsx
settings/
page.tsx
blog/
page.tsx
[slug]/
page.tsx
In questo modo, le pagine di marketing, l'interfaccia utente dell'applicazione e i percorsi dei contenuti rimangono chiaramente separati.
Errori comuni
Quando affianco sviluppatori che utilizzano Next.js, questi sono i problemi che riscontro più frequentemente.
1. Mischiare pages/ e app/
Sebbene tecnicamente possibile, crea confusione.
Se inizi con app/, mantieni solo app.
2. Cartelle annidate
Mantieni la struttura semplice.
Preferisci:
dashboard/analytics
Piuttosto che:
dashboard/features/analytics/pages
3. Ignorare i layout
I layout sono una delle funzionalità più potenti di App Router.
Usateli.
Semplificano notevolmente l'architettura.
Considerazioni finali
La directory app/ potrebbe inizialmente sembrare insolita.
Ma una volta che ci si prende la mano, diventa uno dei modi più puliti per strutturare le applicazioni React.
Invece di dover lottare con la configurazione del routing, i wrapper globali e la duplicazione dei layout, si ottiene un'architettura chiara e prevedibile.
- Le cartelle rappresentano i percorsi
- File speciali controllano il comportamento
- I layout gestiscono l'interfaccia utente condivisa
E improvvisamente il tuo progetto sembra molto più... zen.
Se questo articolo ti è stato utile:
- lascia un ❤️
- aggiungi un 🦄
- raccontami nei commenti come organizzi i tuoi progetti
E se apprezzate contenuti di questo tipo, non esitate a seguirmi qui su DEV per altri post su Next.js, architettura e produttività degli sviluppatori.
EDIT: Questa è una versione riadattata in italiano di questo mio precedente articolo: Next.js Folder Zen: Mastering the app/ Directory
Top comments (0)