Next.js à l’Edge : quand « plus rapide » devient plus lent (et comment bien l’architecturer)
Le rendu à l’edge peut être un cheat code — ou une taxe de latence que vous vous infligez. Voici comment choisir entre SSR, SSG, ISR, PPR et Edge Runtime selon le comportement réel des pages, les mécaniques de cache, et ce que vos dashboards afficheront vraiment en production.
L’edge n’est pas une stratégie de performance. C’est un lieu de déploiement.
Ça peut sembler pédant jusqu’au jour où vous voyez une app Next.js « déplacée à l’edge » devenir plus lente en production : TTFB plus élevé, davantage de cache misses, plus d’overhead middleware, une facture compute plus salée, et une équipe incapable d’expliquer pourquoi parce que tout était « instantané en local ».
L’edge n’aide que si vous savez ce que vous y déplacez — et ce que vous forcez à s’exécuter à chaque requête.
Voici une carte pragmatique des architectures Next.js courantes et des compromis qui comptent : latence, coût et complexité. Si vous êtes lead frontend, ingénieur full-stack ou directeur technique en agence, l’objectif est simple : choisir le bon mode de rendu par page, concevoir un cache qui tient face au trafic réel, et tout instrumenter pour pouvoir le prouver.
Le hype de l’Edge vs. les architectures du monde réel
Le pitch marketing est limpide : exécuter plus près des utilisateurs, réduire la latence, livrer des expériences plus rapides.
La réalité est plus brouillonne, parce que la performance est généralement dominée par :
- Le travail à l’origine (requêtes base de données, APIs tierces, auth)
- Le taux de hit du cache (à quelle fréquence vous évitez le travail à l’origine)
- Les waterfalls (fetchs en série et requêtes dépendantes)
- La taille du payload (JS + données)
- Le middleware et la personnalisation (qui forcent un comportement dynamique)
Le compute à l’edge peut réduire la distance réseau entre l’utilisateur et le serveur — mais il peut aussi :
- Augmenter la fréquence des cold starts (selon le provider/runtime)
- Ajouter un coût compute par requête pour des pages qui auraient pu être mises en cache
- Encourager une sur-personnalisation qui détruit la cacheabilité
- Pousser les équipes vers un debug distribué sans logs suffisants
Un modèle mental utile : « Où se fait le travail ? »
Dans Next.js, chaque requête est une combinaison de :
- CDN qui sert une réponse en cache (le plus rapide et le moins cher)
- Compute edge qui génère/transforme une réponse
- Origine régionale/serverless qui génère une réponse
- Backends de données qui font le vrai travail (DB, search, CMS, auth)
Votre mission : maximiser (1), être intentionnel sur (2) et (3), et optimiser sans pitié (4).
Choisir les modes de rendu selon le type de page
Next.js propose plusieurs stratégies de rendu. Traitez-les comme une boîte à outils, pas comme une religion.
SSR (Server-Side Rendering)
Idéal pour : des pages très dynamiques où le contenu doit être frais à chaque requête.
Quand ça marche :
- Dashboards authentifiés
- Pages sensibles au stock/prix (parfois)
- Pages avec des droits/entitlements par requête
Compromis :
- Variance de TTFB plus élevée (dépend du backend)
- Plus difficile à mettre en cache globalement sauf si vous segmentez les réponses
- Peut coûter cher à grande échelle
Conseil pragmatique : le SSR est souvent le bon choix — mais seulement si vous corrigez aussi les patterns d’accès aux données. Du SSR avec une waterfall en 3 étapes vers des APIs tierces, c’est juste « lent, mais plus près ».
SSG (Static Site Generation)
Idéal pour : du contenu qui change rarement et peut être préconstruit.
Quand ça marche :
- Pages marketing
- Documentation
- Articles de blog
- Landing pages evergreen
Compromis :
- Les temps de build peuvent exploser avec de gros catalogues
- La fraîcheur dépend des déclencheurs de rebuild
Conseil pragmatique : en agence, le SSG est le gain par défaut. Démarrez en statique et n’ajoutez du dynamisme que là où ça paie.
ISR (Incremental Static Regeneration)
Idéal pour : des pages majoritairement statiques qui ont besoin d’une fraîcheur périodique sans rebuild complet.
Quand ça marche :
- Pages pilotées par CMS
- Pages produit avec du contenu non temps réel
- Pages catégorie avec une fraîcheur « suffisamment bonne »
Compromis :
- Le comportement stale-while-revalidate peut surprendre les parties prenantes
- La stratégie de revalidation devient une décision produit
Conseil pragmatique : utilisez la revalidation par tags (quand elle est supportée) pour éviter des fenêtres de revalidate temporelles trop grossières.
PPR (Partial Prerendering)
Idéal pour : des pages avec une coque stable et quelques « îlots » dynamiques.
Quand ça marche :
- Ecommerce : infos produit statiques + disponibilité dynamique
- Pages de contenu : article statique + « recommandé pour vous » dynamique
- Expériences connectées : layout statique + module compte dynamique
Compromis :
- Complexité d’architecture : vous devez séparer ce qui est cacheable de ce qui est spécifique à l’utilisateur
- Exige de la discipline sur les frontières de composants et le data fetching
Conseil pragmatique : le PPR est là où beaucoup d’équipes pensent avoir besoin de l’edge. Souvent, PPR + cache intelligent vous donne 80% du bénéfice avec moins de pièces mobiles.
Edge Runtime
Idéal pour : la gestion de requêtes à faible latence, une personnalisation légère, le routage, et des comportements geo-aware.
Quand ça marche :
- A/B testing au niveau requête
- Redirections geo-based et localisation
- Vérifications token/session pour router correctement les utilisateurs
- Génération HTML rapide si les données sont elles aussi rapides et cacheables
Compromis :
- Contraintes runtime (APIs Node indisponibles ; incompatibilités de librairies)
- Complexité de debugging et d’observabilité
- Facile de rendre tout dynamique par accident
L’edge est un multiplicateur. Si votre couche data est lente ou non cacheable, l’edge rend le problème plus distribué globalement — pas résolu.
Des patterns de cache qui tiennent vraiment
Le cache, c’est là où les apps Next.js gagnent ou perdent en production. Vous n’avez pas besoin de « plus d’edge ». Vous avez besoin d’un plan de cache qui colle au comportement des pages.
Pattern 1 : cache CDN pour le trafic public et anonyme
Si une réponse est identique pour beaucoup d’utilisateurs, elle doit être cacheable au CDN.
À utiliser pour :
- Pages marketing
- Docs publiques
- Pages produit publiques (en grande partie)
Règles empiriques :
- Rendez les réponses cacheables par défaut et ne désactivez que si nécessaire
- Évitez les cookies sur les pages que vous voulez mettre en cache ; les cookies impliquent souvent de la personnalisation
Conclusion concrète : un seul header Set-Cookie peut ruiner votre taux de hit.
Pattern 2 : cache fetch Next.js pour les données, pas seulement les pages
Le Next.js moderne encourage le caching au niveau fetch.
À utiliser pour :
- Fetchs de contenu CMS
- Données de catalogue produit
- Appels API non spécifiques à l’utilisateur
À surveiller :
- Trop de cache peut servir des données obsolètes si vous n’avez pas d’histoire de revalidation
- Pas assez de cache force des appels backend répétés, augmentant la latence en queue (tail latency)
Conclusion concrète : mettez en cache les lectures coûteuses et partagées (CMS, catalogue), pas les lectures personnalisées (panier, compte).
Pattern 3 : revalidation par tags (le super-pouvoir friendly agence)
La revalidation basée sur le temps (revalidate: 60) est un instrument grossier. La revalidation par tags est plus proche de la façon dont les équipes contenu travaillent.
À utiliser pour :
- « Quand ce produit change, mettez à jour ces pages »
- « Quand un article de blog est mis à jour, rafraîchissez sa page et les pages de listing »
Pourquoi ça tient dans les vraies orgs :
- Marche bien avec les webhooks CMS (Contentful, Sanity, Strapi, webhooks Shopify)
- Réduit les tickets « pourquoi le site est encore stale ? »
Si les parties prenantes se soucient de la fraîcheur, donnez-leur une invalidation pilotée par événements — pas un timer.
Pattern 4 : données spécifiques utilisateur : cachez autour, pas à travers
La personnalisation est le moyen le plus rapide de détruire le cache.
Meilleure approche :
- Mettre en cache la coque de page
- Récupérer les données spécifiques utilisateur côté client ou via un petit segment dynamique
- Utiliser PPR/îlots dynamiques pour éviter de forcer toute la page en SSR
Exemple concret :
- Page produit : description statique, images, specs
- Dynamique : « Votre prix », « Dans votre magasin local », « Articles dans votre panier »
Pattern 5 : éviter « l’explosion de clés de cache »
Même si vous cachez, vous cachez peut-être trop de variantes.
Causes courantes :
- Cacher par utilisateur alors qu’il suffisait de cacher par pays
- Inclure toute la query string dans les clés de cache alors qu’un seul param compte
- A/B testing qui crée trop de buckets
Conclusion concrète : concevez les clés de cache délibérément : country + language + experimentBucket suffit souvent. userId, presque jamais.
Middleware et personnalisation : à manier avec précaution
Le middleware Next.js est puissant — et souvent mal utilisé.
Piège 1 : middleware obèse qui tourne sur chaque requête
Si le middleware fait du travail lourd (vérification JWT, fetchs distants, routage complexe), vous avez créé une taxe sur chaque page view.
Gardez le middleware :
- Déterministe
- Rapide
- Majoritairement synchrone
- Sans appels réseau autant que possible
Le middleware doit router et annoter, pas fetcher et calculer.
Piège 2 : sur-personnalisation qui force le rendu dynamique
Scénario courant :
- Vous ajoutez une petite feature de personnalisation (ex. « Salut, Sam »)
- Elle nécessite de lire des cookies/auth
- Soudain, toute la route devient dynamique
- Le caching CDN tombe presque à zéro
Correctif :
- Déplacer la personnalisation dans un petit composant côté client
- Ou l’isoler derrière un segment dynamique (PPR/îlot dynamique)
Piège 3 : data fetching en waterfall (le tueur silencieux de l’edge)
L’Edge SSR peut rester lent si votre serveur fait :
- Fetch de session
- Puis fetch du profil utilisateur
- Puis fetch des droits/entitlements
- Puis fetch des recommandations
Correctifs qui marchent :
- Paralléliser les requêtes indépendantes (
Promise.all) - Regrouper les appels dans un endpoint backend-for-frontend (BFF)
- Pré-calculer quand c’est possible (ex. sets de recommandations nocturnes)
Conclusion concrète : optimisez le graphe de dépendances avant de changer de runtime.
Instrumentation : prouver la performance (et le coût)
Si vous ne pouvez pas le mesurer, vous continuerez à livrer du « rapide en local » et du lent globalement.
Quoi mesurer (observabilité minimum viable)
1) Web Vitals (real user monitoring)
Suivez :
- LCP (largest contentful paint)
- INP (interaction to next paint)
- CLS (layout shift)
Utilisez des outils comme :
- Vercel Analytics
- Google Analytics + Web Vitals library
- Sentry (Performance)
- Datadog RUM
2) Server timing et résultats de cache
Logguez et/ou émettez :
- TTFB
- Statut cache : HIT / MISS / STALE (CDN et fetch cache)
- Durée middleware
- Durée de rendu
Technique pratique :
- Ajouter des headers
Server-Timing(ex.mw;dur=5, render;dur=40, db;dur=30) - Corréler avec des request IDs
3) Timing des dépendances backend
Vous avez besoin de visibilité par dépendance :
- Temps de requête DB
- Latence CMS/API
- Latence du provider d’auth
Outils :
- OpenTelemetry + collector
- Sentry spans
- Datadog APM
Quoi logger (pour pouvoir débugger les trucs bizarres)
Logguez des champs structurés :
route,region,runtime(edge vs node)cacheKey(ou un hash sûr)cacheStatususerSegment(anonyme/authentifié, pas de PII)experimentBucketerrorCode+ raison d’échec upstream
Si vous ne logguez pas le statut de cache, vous allez mal diagnostiquer la performance pendant des semaines.
Observabilité des coûts (la partie que les équipes évitent)
Les coûts edge et SSR peuvent surprendre quand :
- Le taux de hit du cache chute
- Le middleware tourne sur chaque requête
- Des bots tapent des routes dynamiques
Suivez :
- Requêtes par route
- Temps compute par route
- Taux de hit du cache par route
- Pourcentage de trafic bot (et s’il bypass le cache)
Action concrète :
- Ajouter de la détection bot et du rate limiting quand c’est approprié
- S’assurer que les bots reçoivent des réponses en cache pour les pages publiques
Une matrice de décision d’architecture pratique (pour la découverte technique)
Utilisez ceci pendant la phase de discovery en agence pour aligner rapidement les parties prenantes. Scorez chaque type de page, puis choisissez l’option la plus simple qui répond aux exigences.
Étape 1 : classer la page par comportement
Pour chaque route majeure, répondez :
- Est-ce spécifique à l’utilisateur ? (aucun / léger / lourd)
- À quel point doit-ce être frais ? (minutes / heures / jours)
- À quel point la donnée est coûteuse ? (peu coûteuse / modérée / coûteuse)
- Quel volume de trafic ? (faible / moyen / élevé)
- Le SEO est-il critique ? (oui / non)
Étape 2 : choisir un mode de rendu par défaut
- SSG si : anonyme + stable + SEO important
- ISR si : anonyme + change régulièrement + SEO important
- PPR si : majoritairement statique + petits modules dynamiques
- SSR (Node) si : authentifié/fortement personnalisé + fraîcheur stricte
- Edge runtime si : vous avez besoin de routage/geo/expériences à la requête et que vous pouvez rester léger
Étape 3 : appliquer des patterns de stratégie de cache
- Pages publiques : cache CDN + fetch cache + revalidation par tags
- Pages hybrides : coque statique + îlots dynamiques pour les données utilisateur
- Pages auth : mettre en cache des fragments de données (quand c’est sûr), pas le HTML complet
Étape 4 : valider contre les modes de panne
Checklist :
- Le middleware va-t-il tourner sur chaque requête ? Si oui, peut-il être simplifié ?
- Des appels réseau dans le middleware ? Si oui, redesign.
- Des cookies sur des pages censées être mises en cache ? Si oui, isoler.
- Des fetchs en waterfall ? Si oui, paralléliser ou agréger.
- A-t-on de la visibilité sur le statut de cache ? Si non, l’ajouter avant le lancement.
Matrice rapide (règles empiriques)
- Site marketing : SSG/ISR + cache CDN agressif
- Hub de contenu (CMS) : ISR + revalidation par tags via webhooks
- PDP ecommerce : PPR (produit statique + disponibilité/panier dynamiques)
- Recherche/listing : ISR ou SSR selon la personnalisation ; mettre en cache les résultats de requête avec soin
- Dashboard : SSR (Node) avec appels backend optimisés ; envisager l’edge uniquement pour le routage/le gating auth
Conclusion : architecturer pour la cacheabilité d’abord, l’edge ensuite
Si vous voulez une architecture Next.js durable, commencez par une question :
Qu’est-ce qui peut être identique pour des milliers d’utilisateurs — et donc mis en cache ?
Ensuite :
- Choisir le mode de rendu le plus simple par route (SSG/ISR/PPR avant SSR)
- Concevoir les clés de cache et la revalidation comme une feature produit (pas une arrière-pensée)
- Traiter le middleware comme un scalpel, pas comme un évier de cuisine
- Instrumenter le statut de cache, les timings backend et les métriques utilisateurs réelles dès le premier jour
Si vous êtes une agence ou un studio, la victoire n’est pas « on a utilisé l’edge ». La victoire, c’est : une performance prévisible, des compromis explicables, et un système qui reste rapide à mesure que le site évolue.
Vous voulez une version de ceci sous forme de worksheet de discovery ?
Si vous partagez votre liste de routes (top 20 pages) et vos sources de données (CMS, DB, commerce, auth), on peut transformer la matrice ci-dessus en une recommandation d’architecture d’une page avec mode de rendu, plan de cache, et l’observabilité minimale nécessaire pour rester honnête en production.
