L’App Router : la philosophie
L’App Router est le système de routage de Next.js depuis la version 13. Dans Next.js 16, c’est la seule approche recommandée. Le principe : chaque dossier dans app/ correspond à un segment d’URL. La présence ou l’absence de certains fichiers dans ce dossier détermine le comportement de la route.
app/
├── page.tsx → /
├── blog/
│ ├── page.tsx → /blog
│ └── [slug]/
│ └── page.tsx → /blog/mon-article
└── dashboard/
├── layout.tsx → layout partagé
├── page.tsx → /dashboard
└── settings/
└── page.tsx → /dashboard/settings
page.tsx — rendre une route accessible
Un dossier n’est accessible en URL que s’il contient un fichier page.tsx. Sans ce fichier, le dossier peut exister mais la route renvoie 404.
// Server Component par défaut — s'exécute côté serveur
export default function BlogPage() {
return (
<main className="max-w-3xl mx-auto py-12 px-4">
<h1 className="text-4xl font-bold mb-8">Le Blog</h1>
<p className="text-gray-600">Accessible sur /blog</p>
</main>
);
}
// Métadonnées SEO spécifiques à cette page
export const metadata = {
title: 'Blog',
description: 'Tous nos articles',
};
layout.tsx — le layout partagé
Un layout.tsx enveloppe toutes les pages de son dossier et de tous ses sous-dossiers. Il persiste entre les navigations — il ne se re-render pas quand on change de page. Parfait pour la navbar, le sidebar, le footer.
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex min-h-screen">
{/* Sidebar persistante — ne se re-render pas */}
<aside className="w-64 bg-gray-900 text-white p-6">
<nav className="space-y-2">
<a href="/dashboard" className="block p-2 rounded hover:bg-gray-800">Accueil</a>
<a href="/dashboard/settings" className="block p-2 rounded hover:bg-gray-800">Paramètres</a>
</nav>
</aside>
{/* Contenu de la page courante */}
<main className="flex-1 p-8">
{children}
</main>
</div>
);
}
Les layouts s’emboîtent automatiquement. app/layout.tsx enveloppe tout. app/dashboard/layout.tsx enveloppe uniquement les pages dans dashboard/. Next.js fusionne ces layouts sans que vous ayez à faire quoi que ce soit.
loading.tsx — squelette de chargement
Créez un fichier loading.tsx dans un dossier pour afficher automatiquement un état de chargement pendant que la page se charge. Next.js utilise React Suspense en coulisses.
export default function Loading() {
return (
<div className="max-w-3xl mx-auto py-12 px-4 space-y-4">
{/* Skeleton cards */}
{[...Array(3)].map((_, i) => (
<div key={i} className="animate-pulse bg-gray-100 rounded-xl h-24" />
))}
</div>
);
}
Grâce à loading.tsx, Next.js affiche immédiatement le squelette pendant que les données de la page se chargent. L’utilisateur voit une réponse instantanée au lieu d’un écran blanc.
error.tsx — gestion des erreurs
error.tsx capture les erreurs runtime dans un dossier et ses enfants, sans planter toute l’application. Important : il doit obligatoirement être un Client Component ("use client") car il utilise des hooks React.
'use client'; // Obligatoire pour error.tsx
export default function Error({
error,
reset,
}: {
error: Error;
reset: () => void;
}) {
return (
<div className="flex flex-col items-center justify-center min-h-96 gap-4">
<h2 className="text-2xl font-bold text-red-600">Une erreur est survenue</h2>
<p className="text-gray-500">{error.message}</p>
<button
onClick={reset}
className="bg-gray-900 text-white px-6 py-2 rounded-xl hover:bg-gray-700"
>
Réessayer
</button>
</div>
);
}
not-found.tsx — page 404 personnalisée
import Link from 'next/link';
export default function NotFound() {
return (
<div className="flex flex-col items-center justify-center min-h-screen gap-6">
<span className="text-8xl font-black text-gray-200">404</span>
<h2 className="text-2xl font-bold">Page introuvable</h2>
<Link href="/" className="text-blue-600 hover:underline">
Retour à l'accueil
</Link>
</div>
);
}
Récapitulatif : les fichiers spéciaux
page.tsx → Rend la route accessible en URL
layout.tsx → Enveloppe les pages enfants (persiste)
loading.tsx → Affiché pendant le chargement (Suspense)
error.tsx → Capture les erreurs runtime ("use client")
not-found.tsx → Page 404 personnalisée
template.tsx → Comme layout mais se re-render à chaque nav
default.tsx → Fallback pour les parallel routes
Exercice pratique
- Créez une section
app/blog/avec unepage.tsxqui liste 3 articles fictifs - Ajoutez un
layout.tsxdansapp/blog/avec un titre « Le Blog » en en-tête - Ajoutez un
loading.tsxavec 3 blocsanimate-pulse - Ajoutez un
not-found.tsxà la racine du projet et vérifiez qu’il s’affiche sur une URL inexistante - Observez dans les DevTools React que le layout ne se re-render pas lors de la navigation