WC
Retour aux articles

Next.js 16 en production : ce qui a vraiment changé pour les développeurs

9 min read
Partager
Next.js 16 en production : ce qui a vraiment changé pour les développeurs
# Next.js 16 en production : ce qui a vraiment changé pour les développeurs
 
On était en octobre 2025 quand Vercel a sorti Next.js 16. J'avais déjà survécu à la migration vers Next.js 13 (App Router, tout le monde s'en souvient), puis 14 avec ses breaking changes sur le caching, et 15 avec ses async params qui m'avaient coûté une matinée entière. Alors quand j'ai vu la release note, j'ai pris mon café et j'ai lu attentivement avant de faire quoi que ce soit.
 
Voilà ce que j'ai trouvé après plusieurs semaines en production sur plusieurs projets.
 
---
 
## La vraie nouveauté : Turbopack par défaut
 
C'est le changement le plus immédiatement visible. Depuis Next.js 16, lancer `next dev` active Turbopack automatiquement. Plus besoin du flag `--turbopack` qu'on avait depuis Next.js 15.
 
```bash
# Next.js 15 — on devait être explicit
next dev --turbopack
 
# Next.js 16 — c'est le défaut
next dev

En pratique, ça change quoi ? Sur mes projets, le cold start est passé de ~4-6 secondes à moins d'une seconde. Le HMR (hot module replacement) est quasi-instantané, même sur des pages avec beaucoup de composants. C'est la différence entre "je sauvegarde et j'attends" et "je sauvegarde et c'est déjà là".

Ce qui m'a surpris : aucune régression sur mes plugins webpack custom. Turbopack a maintenant une compatibilité suffisante pour que la grande majorité des projets migrent sans toucher à leur config. J'ai eu un seul loader problématique sur un vieux projet legacy — tout le reste a fonctionné out of the box.

Si vous avez une raison de revenir à webpack en dev (rare, mais ça arrive) :

next dev --no-turbopack

isolatedDevBuild et le dossier .next/dev

C'est le changement qui m'a causé le plus de confusion au départ, non pas parce qu'il est complexe, mais parce que je ne l'avais pas lu.

Next.js 16 introduit isolatedDevBuild : le serveur de développement écrit maintenant son output dans .next/dev plutôt que directement dans .next. Le build de production garde son chemin habituel dans .next.

.next/
  dev/          ← nouveau : output du serveur de dev
    chunks/
    server/
  server/        ← build de prod, inchangé
  static/

Pourquoi c'est bien ? Avant, si vous lanciez next dev et next build en parallèle (dans une CI un peu aggressive, ou par erreur), les fichiers se mélangeaient. Maintenant les deux processus ont leurs propres espaces de sortie. Plus de corruption silencieuse.

Concrètement, si vous avez des scripts qui parsent .next directement (analyse de bundle, scripts de déploiement maison), vérifiez qu'ils pointent toujours au bon endroit selon le contexte.


Le mécanisme de lockfile : fin des instances multiples

Combien de fois vous est-il arrivé d'ouvrir un nouveau terminal, de taper next dev, et de vous retrouver avec deux serveurs qui tournent sur le même port et des comportements bizarres ?

Next.js 16 résout ça avec un lockfile. Quand vous lancez next dev, il crée un fichier de verrou dans .next/dev. Si vous essayez de lancer une deuxième instance dans le même projet, vous obtenez un message explicite :

Error: Another Next.js development server is already running for this project.
If the previous instance crashed, delete .next/dev/server.lock and try again.

Simple, efficace. Pas besoin de vérifier lsof -i :3000 ou de killer des processus à l'aveugle. C'est le genre de petite chose qui semblait évidente depuis le début mais qu'on était content de voir arriver.


Node.js 20.9+ : la mise à jour qui fait peur mais qui passe bien

Next.js 16 requiert Node.js 20.9 minimum. Si vous êtes encore sur Node 18 (qui est en fin de vie depuis avril 2025 de toute façon), c'est le moment de migrer.

// package.json — bonne pratique : documenter la contrainte
{
  "engines": {
    "node": ">=20.9.0"
  }
}

Sur mes projets, la migration Node 18 → Node 20 s'est passée sans surprises. Les breaking changes de Node 20 par rapport à 18 sont mineurs pour la plupart des usages. Ce qui peut vous bloquer : des packages natifs très anciens, ou des accès directs à des APIs Node qui ont changé de comportement. Un npm audit + quelques jours de tests suffisent généralement.


Les parallel route slots : default.js n'est plus optionnel

Là, c'est le breaking change qui a fait mal sur un de mes projets.

En Next.js 15, les default.js dans les parallel routes étaient recommandés mais pas toujours nécessaires. Next.js avait un comportement de fallback implicite. En Next.js 16, les slots de parallel routes requièrent des fichiers default.js explicites.

Si vous utilisez la syntaxe @slot dans votre App Router :

app/
  @modal/
    page.tsx
    default.js  ← maintenant obligatoire
  @sidebar/
    page.tsx
    default.js  ← maintenant obligatoire
  layout.tsx
  page.tsx

Sans le default.js, vous obtenez une erreur au build. Le contenu minimal :

// app/@modal/default.js
export default function Default() {
  return null;
}

C'est une décision qui fait sens : le comportement implicite créait des bugs subtils où une navigation causait l'affichage d'un slot vide de façon inattendue. Rendre le fichier obligatoire force à être explicite sur ce qui doit s'afficher (ou ne pas s'afficher) quand le slot n'est pas actif.

Action de migration : faites un grep dans votre projet avant d'upgrader.

# Trouver tous les parallel route slots
find . -type d -name "@*" -not -path "*/node_modules/*"
# Vérifier lesquels n'ont pas de default.js

Le nouveau système de cache : CacheComponents et unified caching layer

C'était l'un des sujets les plus attendus. Le caching de Next.js avait une réputation (méritée) d'être difficile à comprendre et à prévoir.

Next.js 16 introduit une couche de cache unifiée avec une nouvelle primitive : CacheComponents.

import { unstable_cache } from 'next/cache';
 
// Avant — chaque type de cache avait sa propre API
const data = await unstable_cache(
  async () => fetchFromDB(),
  ['cache-key'],
  { revalidate: 3600 }
)();
 
// Nouveau — unified caching layer, API plus cohérente
import { cache } from 'next/cache';
 
const getUser = cache(async (id: string) => {
  return await db.users.findOne(id);
}, {
  tags: ['users'],
  revalidate: 3600
});

La vraie amélioration est en coulisses : le cache de fetch, le cache de route, et le cache de composant partagent maintenant la même infrastructure. Ce qui veut dire que revalidateTag('users') invalide tout ce qui est tagué users, peu importe où dans votre app les données ont été mises en cache. Plus de surprises où on invalidait le fetch cache mais pas le route cache.

// Dans une Server Action
'use server';
import { revalidateTag } from 'next/cache';
 
export async function updateUser(id: string, data: UserData) {
  await db.users.update(id, data);
  revalidateTag('users'); // invalide tout ce qui est tagué 'users'
}

J'ai eu des cas en Next.js 14-15 où les pages restaient en cache après une mutation parce que j'avais oublié de cibler le bon type de cache. Avec la couche unifiée, ce genre d'erreur est beaucoup plus rare.


Ce qui vient de Next.js 15 et qui mérite d'être rappelé

Si vous sautez directement de Next.js 14 à 16, plusieurs features importantes sont arrivées en 15 et sont maintenant stables :

View Transitions API (arrivée en 15.2) : les transitions de page natives du navigateur, sans librairie tierce. Ça s'active avec un flag dans next.config:

// next.config.ts
const nextConfig = {
  experimental: {
    viewTransition: true
  }
};

Node.js Middleware Runtime stable (15.5) : le middleware pouvait enfin utiliser des APIs Node.js natives. En 16, c'est évidemment toujours là et stable.

Support Rspack (15.3) : alternative à webpack pour le build de production (pas le dev, qui est Turbopack). Encore expérimental mais utilisable pour les projets qui ont des contraintes spécifiques sur la phase de build.


La migration en pratique : mon retour d'expérience

J'ai migré trois projets de Next.js 15 vers 16. Voici ce que j'aurais aimé savoir avant.

Ce qui s'est passé sans friction :

  • Turbopack par défaut (aucun changement à faire)
  • Le lockfile (transparent)
  • Le cache unifié (les APIs sont backward-compatible)
  • Node.js 20.9 (déjà sur 20 depuis un moment)

Ce qui a nécessité du travail :

  1. Les default.js dans les parallel routes — j'en avais 6 à ajouter sur un projet
  2. Des scripts de CI qui listaient le contenu de .next directement — à adapter pour .next/dev vs .next
  3. Un loader webpack custom que j'avais dans next.config — incompatible avec Turbopack, j'ai dû trouver une alternative

Temps de migration total : entre 30 minutes (projet simple) et 3 heures (projet avec beaucoup de parallel routes et config webpack custom).

# Commande de migration
npm install next@16 react@19 react-dom@19
 
# Vérifier les peer deps
npm ls next

Ce que j'attends pour la suite

Next.js 16 est une release solide. Elle consolide beaucoup de choses qui étaient expérimentales ou instables dans les versions précédentes. Turbopack par défaut est le signal que l'écosystème est prêt pour ce changement — et les chiffres de performance en dev le confirment largement.

Ce qui me manque encore : une meilleure histoire autour du debugging de cache. Même avec la couche unifiée, comprendre pourquoi une page est en cache (ou ne l'est pas) reste trop opaque. Il y a des outils en cours de développement du côté de Vercel, mais rien de vraiment satisfaisant en dehors de leur infrastructure.

Mais globalement, après quelques semaines en production : pas de regrets. La DX en dev est nettement meilleure, les comportements sont plus prévisibles, et les rares breaking changes sont bien documentés.

Si vous êtes encore sur Next.js 15 (sorti il y a moins d'un an), prenez deux heures, lisez le changelog, faites le grep des parallel routes, et lancez la migration. Vous ne reviendrez pas en arrière.


Cet article a été écrit en mars 2026, basé sur Next.js 16.1.7 (janvier 2026).

Cet article vous a plu ?

Articles similaires

Commentaires

Connectez-vous avec GitHub pour participer a la discussion.