Next.js Memory Leak : Fetch + Mode Standalone — 2 ans sans correctif
Next.js patche le fetch global et ajoute une couche de cache qui fuit à chaque requête. Sous Docker/K8s, cela provoque des crashes OOM toutes les quelques heures. Le bug existe depuis Next.js 14 et n'est toujours pas résolu dans 16.2.x.
TL;DR
Next.js patche le fetch global et ajoute une couche de cache qui maintient des références sur les données de réponse après qu'elles auraient dû être libérées. Chaque appel fetch ajoute de la mémoire qui n'est jamais rendue au GC. Sous Docker/Kubernetes, cela provoque des crashes OOM toutes les quelques heures. Le bug existe depuis Next.js 14 (avril 2024) et n'est toujours pas résolu dans 16.2.x (mars 2026). Sur Vercel, le problème ne se manifeste pas grâce aux fonctions serverless éphémères.
Comment fonctionne un fetch normal
Request → fetch → got data → response to user → GC cleans up → memory freeComment fonctionne fetch dans Next.js
Next.js intercepte le fetch global et l'enveloppe avec sa propre couche de cache/tracking :
Request → Next.js fetch wrapper → creates:
- Performance entry (speed tracking) ← not cleaned
- Request metadata object ← not cleaned
- Internal promise wrapper ← not cleaned
- Cache lookup entry ← not cleaned
- Response body (for unique URL) ← not cleaned
→ Response to user
→ GC sees objects are still referenced → doesn't touch them
→ Memory grows indefinitelyCe qui se passe en production
Self-hosted (Docker/K8s):
Request 1: fetch → +100KB → RAM: 100KB
Request 2: fetch → +100KB → RAM: 200KB
Request 1000: fetch → +100KB → RAM: 100MB
Request 50,000: fetch → +100KB → RAM: 5GB → OOM Kill 💀
→ Kubernetes restarts the pod → cycle repeats
Vercel (Serverless):
Request 1: [start] → fetch → +100KB → [process dies] → 0 KB ✅
Request 2: [start] → fetch → +100KB → [process dies] → 0 KB ✅
→ Memory never accumulatesVersions affectées
Next.js — Toutes les versions avec App Router
| Version | Issue | Date |
|---|---|---|
| 14.2.x | #64212 | April 2024 |
| 14.x-15.x | #68578 | August 2024 |
| 14.3.0-canary | #79588 | May 2025 |
| 16.0.1 | #85914 | November 2025 |
| 16.1.0 | #88603 | January 2026 |
| 16.0.10 | #90433 | February 2026 |
| 16.2.0-canary.51 | Confirmed in #90433 comments | March 2026 |
Node.js
Testé sur Node.js 20, 22, 24, 25 — fuite sur tous.
Ce qui ne fonctionne pas
| Attempt | Result |
|---|---|
cacheMaxMemorySize: 0 | Doesn't help — leak is not from this cache |
| Disable image optimization | Doesn't help |
--max-old-space-size=6144 | Just crashes slower |
Read response via .json() / .text() | Doesn't help |
| Remove React fetch patching (canary.45) | Doesn't help |
| Upgrade to latest version | Doesn't help (leaks on 16.2.0-canary.51 too) |
Ce qui fonctionne (contournements)
| Workaround | Why it helps |
|---|---|
Replace fetch with axios | Bypasses Next.js wrapper |
Replace fetch with node-fetch | Same reason |
| Downgrade Node.js to 20.15.1 | Older undici has fewer leaks (for some) |
Docker image node:20-alpine3.21 | Helps in some cases |
| Deploy to Lambda (SST + OpenNext) | Ephemeral functions — memory doesn't accumulate |
| Deploy to Vercel | Same — serverless |
Limitation du contournement axios
Vos propres appels API peuvent être remplacés par axios. Mais Next.js utilise en interne le fetch patché pour :
- ISR (Incremental Static Regeneration)
revalidatePath/revalidateTag- Data fetching des Server Components avec déduplication
use cache(Next.js 16)
Même sans un seul fetch dans votre code — Next.js l'utilise toujours en interne.
Pourquoi Vercel ne corrige pas
Logique business
Vercel est une entreprise qui gagne de l'argent en hébergeant Next.js. Sur leur plateforme, le problème ne se manifeste pas (serverless = éphémère). Le bug n'affecte que le self-hosted (Docker, K8s, VPS) — ceux qui ne paient pas Vercel.
Position officielle
Tim Neutkens (mainteneur Vercel) a analysé le problème et déclaré que c'est un problème d'undici (bibliothèque fetch de Node.js), pas de Next.js. L'issue #90433 a été fermée. Malgré le fait que :
- axios et node-fetch sur le même Node.js fonctionnent sans fuites
- La fuite n'apparaît que quand fetch passe par le wrapper Next.js
- Le bug est ouvert depuis 2 ans sans correction
Priorités
En 2 ans, l'équipe Next.js a livré :
- Turbopack (builds 2-5x plus rapides) — avantage marketing
- Cache Components /
use cache— réduit la charge sur les serveurs Vercel proxy.tsau lieu du middleware — simplifie le déploiement edge sur Vercel- DevTools MCP — hype IA
Memory leak en self-hosted ? Pas une priorité.
Solution : AWS Lambda (SST + OpenNext)
Qu'est-ce que c'est
OpenNext est un adaptateur open-source qui convertit un build Next.js en format pour AWS Lambda. SST est un framework qui automatise l'infrastructure.
Architecture
Next.js build
→ OpenNext
→ AWS Lambda (SSR, API routes)
→ S3 (static, assets)
→ CloudFront (CDN)
→ SQS + DynamoDB (ISR revalidation)Pourquoi cela résout le memory leak
Les fonctions Lambda traitent les requêtes et sont recyclées après 5-15 minutes d'inactivité. La mémoire n'a pas le temps de s'accumuler.
Déploiement
npx sst@latest init
npx sst deploy --stage productionComparaison
| Vercel | AWS Lambda (SST) | Docker self-hosted | |
|---|---|---|---|
| Memory leak | Not felt | Not felt | Critical |
| Cold starts | Yes | Yes (~200-500ms) | No |
| Price (~medium traffic) | $20-150/mo | $5-30/mo | $5-50/mo |
| Control | Minimal | Full | Full |
| ISR/Revalidation | Works | Works (SQS) | Works (with leak) |
| Vendor lock-in | Vercel | AWS | None |
Nuances Lambda
- Cold starts — la première requête est plus lente (~200-500ms)
- Sécurité — activer OAC (Origin Access Control), sinon l'URL Lambda est publique
- OpenNext — projet communautaire, pas officiel Vercel. Les nouvelles fonctionnalités Next.js peuvent casser
- Attaque au portefeuille — lors d'un DDoS, l'auto-scaling Lambda peut mener à une grosse facture
Pourquoi une vraie correction est irréaliste
1. Problème architectural
La fuite n'est pas un bug accidentel mais la conséquence d'une décision de conception : Next.js intercepte le fetch global et ajoute du cache/tracking par-dessus. Pour corriger, il faudrait repenser la façon dont App Router interagit avec fetch. Cela touche ISR, revalidation, data cache, request deduplication — le cœur du framework.
2. Conflit d'intérêts
Vercel n'est pas motivé à corriger ce qui n'affecte pas sa plateforme. Le self-hosted est en concurrence avec leur business. Plus il y a de problèmes en self-hosted — plus de gens migrent vers Vercel.
3. Rejet de la faute
La position officielle est "c'est undici, pas nous". Tant que cela ne change pas — ils ne travailleront pas sur un correctif.
4. Pas de correctif communautaire
La licence AGPL-3.0 de Next.js autorise les forks, mais la base de code est énorme et étroitement couplée à l'infrastructure Vercel. Un PR communautaire pour corriger le wrapper fetch nécessiterait une compréhension approfondie de l'architecture interne et l'approbation des mainteneurs — qui ont déjà fermé l'issue.
Conclusions
- Si sur Vercel — pas de problème, rien à faire
- Si self-hosted et besoin de serverless — SST + OpenNext sur AWS Lambda
- Si self-hosted Docker — remplacer fetch par axios où possible, surveiller la RAM, configurer le redémarrage automatique des pods
- Si nouveau projet — envisager SvelteKit ou Nuxt comme alternatives sans ce problème
Sources
- Issue #64212 — Memory Leak with global fetch (April 2024)
- Issue #68578 — Possible memory leak in Fetch API (August 2024)
- Issue #85914 — Memory Leak with fetch + standalone (November 2025)
- Issue #90433 — OOM in 16.0.10 (February 2026)
- Discussion #88603 — OOM in Docker/K8s (January 2026)
- Discussion #88078 — cacheMaxMemorySize behavior
- OpenNext
- SST — Next.js on AWS
- Secret knowledge to self-host Next.js
- Next.js Memory Usage Guide