Skip to content
griban.dev
← retour_au_blog
nextjs

Performance du Next.js App Router : Optimiser Next.js 15 & 16

Ruslan Griban10 min de lecture
partager:

La sortie de Next.js 15 et 16 marque un tournant décisif dans notre approche de la performance web. Nous avons quitté l'ère de la mise en cache implicite "magique" pour entrer dans une ère de contrôle explicite et granulaire. Avec l'introduction de la version stable du React Compiler, du Partial Prerendering (PPR) et de la directive révolutionnaire use cache, l'App Router a mûri pour devenir un moteur de haute performance capable de livrer des temps de chargement inférieurs à la seconde, même pour des applications complexes et riches en données.

Optimiser une application Next.js en 2025 ne consiste plus seulement à minifier le JavaScript ; il s'agit d'orchestrer le mouvement des données entre le serveur et le client avec une précision chirurgicale. Ce guide explore les techniques avancées nécessaires pour maîtriser la performance dans l'écosystème moderne de Next.js.

La révolution du cache : de l'implicite à l'explicite

Dans les versions précédentes de l'App Router, la mise en cache était souvent "implicite". Un simple appel à une fonction dynamique comme cookies() ou headers() pouvait, de manière inattendue, désactiver le cache pour toute une route. Next.js 16 a fondamentalement changé cela avec le modèle "Cache Components".

La directive use cache

La directive use cache est l'avancée la plus significative de Next.js 16. Elle permet aux développeurs d'opter explicitement pour la mise en cache au niveau d'une fonction ou d'un fichier. Cela met fin à l'imprévisibilité du modèle de cache précédent.

  • Mise en cache au niveau de la fonction : Vous pouvez désormais envelopper une logique spécifique (comme une requête de base de données ou un appel API externe) dans une fonction asynchrone et la marquer avec 'use cache';. Next.js mettra en cache la valeur de retour en fonction des arguments sérialisés.
  • Mise en cache au niveau du fichier : Placer 'use cache'; en haut d'un fichier met en cache chaque fonction exportée dans ce fichier.
// services/products.ts
import { unstable_cacheLife as cacheLife } from 'next/cache';
 
export async function getProductDetails(productId: string) {
  'use cache'; // Opter explicitement pour la mise en cache de cette fonction
  cacheLife('minutes'); // Définir le profil d'expiration
 
  const res = await fetch(`https://api.acme.com/products/${productId}`);
  if (!res.ok) throw new Error('Failed to fetch product');
  
  return res.json();
}

API de contrôle granulaire du cache

Pour accompagner ce modèle explicite, Next.js a introduit plusieurs nouvelles API pour la gestion du cache :

  1. cacheLife : Remplace les anciennes constantes de revalidate. Elle accepte des profils tels que 'minutes', 'hours' ou 'days', facilitant la gestion du TTL (Time To Live) à travers différents environnements.
  2. cacheTag et revalidateTag : Ils restent la référence absolue pour l'invalidation à la demande. En taguant un segment mis en cache, vous pouvez le purger immédiatement lorsque les données changent (par exemple, après un webhook de CMS).

Un diagramme technique montrant l'architecture du cache de Next.js 16, illustrant comment la directive 'use cache' interagit avec le Data Cache et le Client-side Router Cache pour servir les requêtes efficacement.

Maîtriser les modèles de rendu : PPR et Streaming

L'objectif de l'optimisation de la performance est de réduire le Time to First Byte (TTFB) et l'Interaction to Next Paint (INP). Next.js 16 y parvient grâce à la stabilisation du Partial Prerendering (PPR).

Partial Prerendering (PPR) Stable

Le PPR vous permet de combiner rendu statique et dynamique sur la même page sans configuration complexe. Lorsqu'un utilisateur demande une page, Next.js sert immédiatement une coque HTML statique (contenant votre mise en page, la navigation et le contenu statique). Les "zones dynamiques" — les parties de la page qui nécessitent des données spécifiques à l'utilisateur — sont enveloppées dans des limites <Suspense> et sont envoyées en streaming au fur et à mesure de leur résolution.

Pour activer le PPR, configurez-le dans votre next.config.js :

// next.config.js
const nextConfig = {
  experimental: {
    ppr: 'incremental', // Adopter progressivement le PPR sur vos routes
  },
};
module.exports = nextConfig;

Le rôle de React 19 et du React Compiler

Next.js 16 tire parti de la version stable du React Compiler. Auparavant, les développeurs passaient beaucoup de temps à optimiser manuellement les composants avec useMemo, useCallback et React.memo pour éviter les re-rendus inutiles. Le React Compiler automatise ce processus en analysant votre code et en appliquant la mémoïsation là où elle est la plus bénéfique.

Cela se traduit par :

  • Réduction du travail sur le thread principal : Les composants ne se re-rendent que lorsque leurs dépendances de données réelles changent.
  • Amélioration de l'INP : En réduisant le travail effectué par React lors des mises à jour, le navigateur reste réactif aux entrées de l'utilisateur.

Stratégies de récupération de données haute performance

La récupération de données (data fetching) est souvent le principal goulot d'étranglement des applications web. Dans l'App Router, nous devons nous éloigner des "cascades" (waterfalls) séquentielles pour privilégier l'exécution parallèle et le streaming.

Éliminer les cascades de requêtes

Un piège courant consiste à attendre plusieurs appels fetch les uns après les autres. Cela force la deuxième requête à attendre la fin de la première, doublant ainsi votre latence.

L'Anti-Pattern (Lent) :

const user = await getUser(); // Prend 500ms
const posts = await getPosts(user.id); // Prend 500ms (Total : 1000ms)

Le modèle optimisé (Rapide) :

// Initier les deux requêtes en parallèle
const userPromise = getUser();
const postsPromise = getPosts();
 
// Attendre que les deux soient résolues
const [user, posts] = await Promise.all([userPromise, postsPromise]);

Exploiter les Server Components pour l'optimisation des "feuilles"

Pour minimiser le bundle JavaScript envoyé au client, vous devriez garder vos "Client Components" aux extrémités (les feuilles) de votre arbre de composants. Si vous marquez une mise en page de haut niveau avec "use client", chaque composant importé dans cette mise en page devient partie intégrante du bundle client.

Au lieu de cela, passez les Server Components comme enfants ou props aux Client Components pour conserver l'avantage du "Server-First".

// Mauvais : Toute la page est un Client Component
"use client"
export default function Dashboard({ data }) {
  return <Sidebar>{/* logique complexe */}</Sidebar>;
}
 
// Bon : Seul le bouton interactif est un Client Component
export default function DashboardPage() {
  return (
    <Sidebar>
      <Suspense fallback={<Skeleton />}>
        <DataList /> {/* Server Component */}
      </Suspense>
      <InteractiveToggle /> {/* Client Component */}
    </Sidebar>
  );
}

Une visualisation architecturale montrant un arbre de composants React où les directives 'use client' sont placées aux 'feuilles' (composants les plus bas), soulignant la réduction du JavaScript envoyé au navigateur.

Optimisation des ressources et passage à Turbopack

Les ressources — images, polices et scripts — représentent souvent la majeure partie du poids d'une page. Next.js fournit des primitives intégrées pour les gérer automatiquement.

Optimisation des images avec next/image

Le composant next/image est bien plus qu'une simple balise <img>. En 2025, il est essentiel d'utiliser l'attribut priority pour les éléments du Largest Contentful Paint (LCP) et l'attribut sizes pour empêcher le navigateur de télécharger des images trop grandes pour la fenêtre d'affichage (viewport).

<Image
  src="/hero.jpg"
  alt="Image d'accueil"
  width={1200}
  height={600}
  priority // Essentiel pour le LCP
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>

Optimisation des polices et zéro décalage de mise en page

L'utilisation de next/font vous permet d'héberger des polices localement et gère automatiquement la propriété font-display. Cela élimine le décalage de mise en page (CLS) causé par le chargement des polices après le rendu initial. En utilisant des variables CSS avec next/font, vous vous assurez que votre typographie est prête dès que le HTML est analysé.

Turbopack : le nouveau standard

Avec Turbopack désormais comme bundler par défaut dans Next.js 16, les temps de build et les vitesses de Fast Refresh se sont considérablement améliorés. Turbopack utilise un moteur de calcul incrémental écrit en Rust, qui ne recompile que le code exact qui a été modifié. Pour les applications à grande échelle, cela peut réduire les temps de build en production jusqu'à 80 %.

Surveillance et validation en conditions réelles

L'optimisation de la performance n'est pas une tâche ponctuelle. Vous devez valider vos améliorations à l'aide du Real User Monitoring (RUM).

  1. Vercel Speed Insights : Cet outil fournit un tableau de bord en direct des Core Web Vitals de votre application (LCP, INP, CLS) basé sur les données réelles des utilisateurs.
  2. Sentry et OpenTelemetry : Pour des analyses plus approfondies, notamment dans les Server Components et les routes d'API, utilisez le traçage basé sur OpenTelemetry. Cela vous permet de voir exactement quelle requête de base de données ou quel appel API externe ralentit votre rendu côté serveur (SSR).
  3. Zod pour la sécurité à l'exécution : Bien qu'il ne s'agisse pas d'un outil de "vitesse" direct, l'utilisation de Zod pour valider les réponses API garantit que votre application ne plante pas ou ne reste pas bloquée à cause de formats de données inattendus, ce qui peut nuire à la performance perçue.

Une capture d'écran d'un tableau de bord de surveillance des performances montrant les scores Core Web Vitals (LCP, FID, CLS) et un graphique en cascade des requêtes réseau dans une application Next.js.

Foire aux questions

Comment optimiser la performance dans le Next.js App Router ?

L'optimisation dans l'App Router repose sur l'utilisation des Server Components par défaut pour réduire le JavaScript côté client et l'implémentation du Partial Prerendering (PPR) pour des chargements initiaux rapides. De plus, exploitez la directive use cache pour une mise en cache granulaire des données et assurez-vous d'utiliser next/image et next/font pour l'optimisation des ressources.

Le Next.js App Router est-il plus rapide que le Pages Router ?

L'App Router est généralement plus rapide car il permet d'utiliser les React Server Components (RSC), qui réduisent considérablement la quantité de JavaScript envoyée au navigateur. Il prend également en charge des fonctionnalités avancées telles que le Streaming et le Partial Prerendering qui ne sont pas disponibles dans le Pages Router, ce qui améliore les Core Web Vitals.

Comment réduire la taille du bundle JavaScript dans Next.js ?

Pour réduire la taille du bundle, déplacez l'interactivité vers les "feuilles" de votre arbre de composants et utilisez des imports dynamiques (next/dynamic) pour les bibliothèques tierces lourdes. Évitez de placer la directive "use client" au niveau supérieur de vos mises en page, car cela force tous les composants enfants à être inclus dans le bundle client.

Comment fonctionne la mise en cache dans le Next.js App Router ?

Dans Next.js 16, la mise en cache est explicite via la directive use cache, vous permettant de mettre en cache des fonctions ou des fichiers avec des profils TTL spécifiques via cacheLife. Il utilise également un système de mise en cache à plusieurs niveaux, incluant la Request Memoization, le Data Cache et le Full Route Cache, afin de minimiser les traitements redondants.

Quelles sont les meilleures pratiques pour la récupération de données dans Next.js ?

Récupérez toujours les données sur le serveur à l'aide des Server Components pour garder la logique proche de la source de données et réduire la charge côté client. Utilisez la récupération parallèle avec Promise.all pour éviter les cascades (waterfalls) et enveloppez les récupérations de données lentes dans des limites <Suspense> pour permettre le streaming et offrir une meilleure expérience utilisateur.

Conclusion

Optimiser la performance dans le Next.js App Router est un chemin vers un contrôle explicite. En adoptant la directive use cache, en exploitant le Partial Prerendering et en laissant le React Compiler gérer les optimisations de bas niveau, vous pouvez construire des applications qui sont non seulement rapides, mais aussi résilientes et faciles à maintenir.

Alors que nous regardons vers l'avenir du web en 2025 et 2026, l'accent est passé de "combien pouvons-nous envoyer au client" à "de combien avons-nous réellement besoin". En suivant ces bonnes pratiques, vous garantissez que vos applications Next.js restent à la pointe de la vitesse et de l'expérience utilisateur.

rocket_launch

Ready to start your project?

Let's discuss how I can help bring your ideas to life with modern web technologies and AI.

Get in Touch