Next.js 16 App Router et SSR en 2026 — guide technique complet
Next.js 16.2.1 (18 mars 2026) apporte Turbopack par défaut, la directive « use cache », proxy.ts remplaçant middleware.ts, et le React Compiler stable. Ce guide couvre les Server Components, le Streaming SSR avec Suspense, et le nouveau modèle de cache — avec du code TypeScript prêt à l'emploi.

Next.js 16 : les changements fondamentaux
- Turbopack par défaut : jusqu'à 10× Fast Refresh plus rapide, FS caching stable
"use cache"remplace le cache implicite — modèle opt-in expliciteproxy.tsremplacemiddleware.ts(déprécié) — runtime Node.js complet- React Compiler stable : plus besoin de
useMemo/useCallback - Breaking changes :
params,searchParams,cookies(),headers()sont async (il fautawait) - Next.js 16.2 : ~400 % startup plus rapide, désérialisation RSC 350 % plus rapide
React Server Components : le modèle mental
Par défaut, tous les composants dans app/ sont des Server Components. "use client" crée une frontière client. Règle d'or : pousser "use client" aux composants feuilles uniquement.
// app/products/page.tsx — Server Component par défaut
export default async function ProductsPage() {
const products = await fetch('https://api.example.com/products', {
next: { revalidate: 3600 }
}).then(r => r.json());
return (
<div>
<h1>Produits</h1>
{products.map(p => <div key={p.id}><h2>{p.name}</h2></div>)}
</div>
);
}Streaming SSR avec Suspense
Le serveur envoie immédiatement la structure statique, puis streame les parties dynamiques :
import { Suspense } from 'react';
export default function DashboardPage() {
return (
<>
<Header /> {/* Affiché immédiatement */}
<Suspense fallback={<OrdersSkeleton />}>
<RecentOrders /> {/* Streamé quand prêt */}
</Suspense>
<Suspense fallback={<AnalyticsSkeleton />}>
<Analytics /> {/* Streamé indépendamment */}
</Suspense>
</>
);
}loading.tsx : fallback Suspense automatique par route. Chaque frontière Suspense est une unité de streaming indépendante.
Data fetching et cache en 2026
Le fetch est no-store par défaut (plus de cache implicite). Le nouveau modèle :
"use cache"avec profilscacheLife('hours')/cacheTag('products')revalidateTag()nécessite un 2e argument (profil cacheLife)'use cache: remote'pour stockage distant
'use server'
import { revalidatePath } from 'next/cache';
import { z } from 'zod';
const schema = z.object({ name: z.string().min(1), email: z.string().email() });
export async function createUser(formData: FormData) {
const parsed = schema.safeParse({
name: formData.get('name'), email: formData.get('email')
});
if (!parsed.success) return { error: 'Données invalides' };
await db.user.create({ data: parsed.data });
revalidatePath('/users');
redirect('/users');
}Les pièges qui font perdre des heures
- Erreurs d'hydratation :
Math.random(),Date.now(),windowdans le rendu JSX → utiliseruseEffect "use client"trop haut dans l'arbre → tout devient Client Component- Cache dev ≠ prod → toujours tester avec
npm run build && npm start - Server Actions pour le data fetching : elles utilisent POST, non cacheable
- CVE-2025-55182 (React2Shell) : vulnérabilité critique RSC corrigée en décembre 2025 — mettez à jour