Audit de code Next.js : ce que nous vérifions sur une application en production, et comment commencer vous-même
Ce que couvre un audit Next.js : frontière serveur/client, Server Actions, cache de Next.js 14 à 16, poids des bundles, montées de version et auto-hébergement.
Points clés
- Un audit Next.js n'est pas une revue de code générique. Les constats les plus graves se trouvent dans des zones propres au framework : la frontière serveur/client, les Server Actions, le cache et la façon dont l'application est déployée.
- Les règles de cache ont changé deux fois en deux ans. Next.js 15 a cessé de mettre en cache par défaut
fetch, les Route HandlersGETet les navigations ; Next.js 16 a rendu le cache explicite avec"use cache". Une application montée de version sans revoir son cache sert souvent des données périmées, voire partagées à tort.- L'abus de
"use client"est le constat de performance le plus fréquent : il envoie au navigateur de la logique serveur et de grosses bibliothèques, et ralentit chaque page.- Traitez chaque Server Action et chaque Route Handler comme un point d'accès public. La documentation du framework le dit elle-même.
- Vous pouvez faire un premier passage vous-même en un après-midi avec
next build, un analyseur de bundle, un audit des dépendances et quelques recherches. Les vérifications sont plus bas.
Un audit de code Next.js est une revue structurée du code, de la configuration et du déploiement d'une application Next.js, destinée à trouver ce qui posera problème en production : failles de sécurité, lenteurs, fuites de données entre utilisateurs, montées de version fragiles et angles morts d'exploitation. Il est plus étroit et plus profond qu'un audit technique d'application web général, parce que le framework brouille la frontière entre serveur et navigateur d'une façon qui crée ses propres catégories de bugs. Cet article liste ce que nous vérifions, pourquoi chaque point compte, et ce que vous pouvez regarder vous-même avant de faire appel à quiconque. Pour le durcissement sécurité proprement dit, notre checklist de sécurité Next.js va plus loin.
1. Version, routeur et chemin de montée de version
Nous commençons par la base de l'application, parce que tout le reste en dépend.
- Versions de Next.js et de React. Quel est le retard, et des vulnérabilités publiées restent-elles non corrigées ?
npx next infoaffiche les versions utilisées. - App Router, Pages Router, ou les deux. Les applications mixtes sont fréquentes après une migration partielle ; nous vérifions que la répartition est voulue et documentée.
- Ruptures pas encore absorbées. Next.js 15 a rendu asynchrones les API de requête (
cookies(),headers(),params,searchParams), avec un accès synchrone toléré temporairement derrière des avertissements ; Next.js 16 a supprimé cet accès synchrone, renommémiddleware.tsenproxy.ts, fait de Turbopack le bundler par défaut et exige Node.js 20.9 ou plus (Next.js 15, Next.js 16). Une application dont les logs affichent des avertissements est une application que la prochaine montée de version cassera.
Livrable : un chemin de montée de version réaliste, avec l'effort de chaque étape.
2. La frontière serveur/client
C'est là que nous trouvons le plus de problèmes, en performance comme en sécurité.
- La prolifération de
"use client". Déclarer un composant client fait entrer tout ce qu'il importe dans le bundle navigateur. Nous trouvons régulièrement"use client"en tête de layouts ou de gros composants de page, qui embarquent des bibliothèques de dates, des parseurs Markdown ou des kits d'interface entiers sur chaque page. La correction consiste généralement à repousser la directive vers les petits éléments interactifs. - Du code serveur qui atteint le navigateur. Clients de base de données, utilitaires d'API internes ou modules lisant des secrets importés par un composant qui finit côté client. Le paquet
server-onlytransforme cette erreur en erreur de build ; nous vérifions qu'il est utilisé. - Des props trop généreuses. Un composant serveur qui passe un enregistrement complet de la base à un composant client envoie tous les champs au navigateur, visibles dans la charge utile de la page, même si l'interface n'en affiche que deux.
- Les variables d'environnement. Tout ce qui commence par
NEXT_PUBLIC_est intégré au JavaScript client. Nous les listons toutes et vérifions qu'aucune n'est un secret.
3. Server Actions et Route Handlers
La documentation de Next.js précise qu'une Server Action est accessible comme un point d'accès HTTP public, même si rien dans l'interface ne l'appelle, et recommande de la traiter comme telle (notes de version de Next.js 15). Pour chaque action et chaque route, nous vérifions :
- L'authentification dans l'action elle-même, pas seulement dans la page qui affiche le formulaire, ni seulement dans
proxy.ts. - L'autorisation : cet utilisateur a-t-il le droit d'agir sur cet enregistrement ? L'absence de contrôle de propriété est le constat classique : on change un identifiant dans la requête et on modifie les données de quelqu'un d'autre.
- La validation des entrées par un schéma, et non par confiance dans le formulaire.
- La limitation de débit sur tout ce qui envoie des e-mails, crée des comptes ou coûte de l'argent.
- Ce que l'action renvoie, puisque la valeur de retour part au navigateur.
Nous décrivons la manière de structurer ces contrôles dans structurer l'autorisation.
4. Récupération des données et cache
C'est sur le cache que les applications Next.js se comportent le plus souvent autrement que ne le pensent leurs auteurs, en partie parce que les comportements par défaut ont changé :
| Version | Comportement par défaut |
|---|---|
| Next.js 13–14 (App Router) | Résultats de fetch et Route Handlers GET mis en cache par défaut, sauf désactivation |
| Next.js 15 | Route Handlers GET et segments de page du cache de navigation client plus mis en cache par défaut ; le cache de fetch devient une option |
| Next.js 16 | Cache Components : le cache est explicite avec "use cache", et le code dynamique s'exécute à la requête par défaut ; revalidateTag() prend un profil de cache, updateTag() permet de relire ses écritures dans une Server Action |
Ce que nous cherchons :
- Des données propres à un utilisateur dans un cache partagé. Le plus grave : une fonction ou une page en cache qui lit l'utilisateur courant, de sorte que les données de l'un sont servies à un autre.
- Des données périmées après une écriture, parce que rien ne revalide le bon tag ou le bon chemin.
- Des cascades de requêtes : des
awaitsuccessifs dans une page ou un layout qui pourraient s'exécuter en parallèle, ou des données chargées dans un layout puis à nouveau dans chaque page. - Tout est dynamique par accident. Un seul appel à
cookies()dans le layout racine peut rendre toutes les routes dynamiques. Le tableau des routes affiché parnext buildmontre lesquelles sont statiques.
5. Performance et poids des bundles
- Le JavaScript par route, d'après la sortie du build et un analyseur de bundle, comparé à ce dont chaque page a vraiment besoin.
- Les images :
next/imageutilisé avec dessizescorrects, une priorité sur la plus grande image au-dessus de la ligne de flottaison, et desremotePatternsrestreints (l'ancienimages.domainsest déprécié dans Next.js 16). - Les polices chargées via
next/fontplutôt que par des feuilles de style externes. - Les scripts tiers (statistiques, chat, gestionnaires de balises) chargés avec la bonne stratégie
next/script. - Les Core Web Vitals mesurés sur de vrais utilisateurs quand c'est possible (Search Console, CrUX), en laboratoire sinon, avec l'Interaction to Next Paint sur les pages les plus interactives.
6. Déploiement et exploitation
Beaucoup de problèmes Next.js n'apparaissent qu'une fois l'application sortie de Vercel ou lancée sur plusieurs instances.
- L'auto-hébergement :
output: "standalone", version de Node.js, service des fichiers statiques, présence d'un CDN. - Un cache partagé entre instances. Avec plusieurs conteneurs, la régénération statique incrémentale et le cache de données ont besoin d'un gestionnaire de cache partagé ; sinon chaque instance sert sa propre version d'une page.
- L'observabilité :
instrumentation.tsest-il utilisé, et le hookonRequestErrorenvoie-t-il les erreurs serveur quelque part où quelqu'un les lit ? - En-têtes de sécurité et CSP définis une fois, de façon centralisée.
- La reproductibilité du build : fichier de verrouillage commité, intégration continue qui construit comme la production, environnements de prévisualisation.
7. Santé du code
Les vérifications habituelles restent valables : rigueur de TypeScript, tests sur les règles métier, gestion des erreurs (error.tsx, not-found.tsx), bases de l'accessibilité, et capacité d'un nouvel ingénieur à lancer l'application à partir du README.
Un premier passage à faire vous-même
Pas besoin d'auditeur pour commencer. En un après-midi :
- Versions :
npx next info, puis comparez avec la dernière version et les avis de sécurité. - Tableau des routes : lancez
next buildet lisez la sortie. Les routes censées être statiques le sont-elles ? Certains bundles de premier chargement sont-ils anormalement lourds ? - Bundle : ajoutez
@next/bundle-analyzeret cherchez les grosses bibliothèques dans les bundles client. - Dépendances :
npm audit --omit=dev(ou l'équivalent de votre gestionnaire de paquets). - Recherches dans le code :
"use client"dans les layouts ou dans de très gros fichiers ;NEXT_PUBLIC_, en vérifiant que chaque valeur peut être publique ;"use server", en ouvrant chaque action pour confirmer qu'elle vérifie l'utilisateur et ses droits ;dangerouslySetInnerHTML, en confirmant que le HTML est assaini ;cookies()ouheaders()dans les layouts racine.
- Logs : cherchez les avertissements de dépréciation en développement et en production ; chacun annonce une future rupture.
Si ces vérifications soulèvent plus de questions qu'elles n'en règlent, c'est le moment où une revue externe se rentabilise.
Ce que livre un audit complet
Un rapport écrit avec chaque constat noté par gravité et par effort, la preuve (fichier et ligne) et la correction recommandée ; une courte liste de ce qu'il faut corriger cette semaine ; un plan de montée de version ; et une restitution avec votre équipe. Sur une application Next.js typique, cela prend d'une à trois semaines selon la taille. La page audit technique décrit notre façon de procéder.
Questions fréquentes
En quoi un audit Next.js diffère-t-il d'une revue de code générale ? Une revue générale examine la qualité du code. Un audit Next.js examine aussi la répartition du code entre serveur et navigateur, le comportement du cache selon les versions, la sécurisation des Server Actions et le fonctionnement de l'application une fois déployée. C'est de là que viennent les problèmes de production propres au framework.
Faut-il passer à Next.js 16 avant ou après un audit ? Plutôt après. L'audit indique ce que la montée de version touchera et ce qu'il faut corriger d'abord, pour ne pas emporter les problèmes existants dans la nouvelle version.
Nous sommes sur le Pages Router. Est-ce un problème ? Pas en soi : le Pages Router est toujours maintenu. La question est de savoir si une migration réglerait un vrai problème pour vous ; un audit doit y répondre, pas le présupposer.
Pouvez-vous auditer une application hébergée sur Vercel ? Oui. L'hébergement change certaines vérifications de déploiement, mais les revues du code, du cache, de la sécurité et de la performance sont les mêmes.
Nous construisons et exploitons des applications Next.js en production, dont ce site. Pour une revue indépendante de la vôtre, voir notre offre d'audit technique ou contactez-nous.
Sources
- Notes de version de Next.js 15 : API de requête asynchrones, sémantique du cache, sécurité des Server Actions,
instrumentation.js - Notes de version de Next.js 16 : Cache Components,
proxy.ts, API de cache, versions requises, dépréciations - Documentation Next.js, Server and Client Components
- Documentation Next.js, configuration
cacheHandler @next/bundle-analyzersur npm