Skip to main content
← Retour au blog
Next.jsMemory LeakDockerAWS LambdaNode.js

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.

Publié 19 mars 202610 min de lecture

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 free

Comment 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 indefinitely

Ce 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 accumulates

Versions affectées

Next.js — Toutes les versions avec App Router

VersionIssueDate
14.2.x#64212April 2024
14.x-15.x#68578August 2024
14.3.0-canary#79588May 2025
16.0.1#85914November 2025
16.1.0#88603January 2026
16.0.10#90433February 2026
16.2.0-canary.51Confirmed in #90433 commentsMarch 2026

Node.js

Testé sur Node.js 20, 22, 24, 25 — fuite sur tous.

Ce qui ne fonctionne pas

AttemptResult
cacheMaxMemorySize: 0Doesn't help — leak is not from this cache
Disable image optimizationDoesn't help
--max-old-space-size=6144Just crashes slower
Read response via .json() / .text()Doesn't help
Remove React fetch patching (canary.45)Doesn't help
Upgrade to latest versionDoesn't help (leaks on 16.2.0-canary.51 too)

Ce qui fonctionne (contournements)

WorkaroundWhy it helps
Replace fetch with axiosBypasses Next.js wrapper
Replace fetch with node-fetchSame reason
Downgrade Node.js to 20.15.1Older undici has fewer leaks (for some)
Docker image node:20-alpine3.21Helps in some cases
Deploy to Lambda (SST + OpenNext)Ephemeral functions — memory doesn't accumulate
Deploy to VercelSame — 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.ts au 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 production

Comparaison

VercelAWS Lambda (SST)Docker self-hosted
Memory leakNot feltNot feltCritical
Cold startsYesYes (~200-500ms)No
Price (~medium traffic)$20-150/mo$5-30/mo$5-50/mo
ControlMinimalFullFull
ISR/RevalidationWorksWorks (SQS)Works (with leak)
Vendor lock-inVercelAWSNone

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

  1. Si sur Vercel — pas de problème, rien à faire
  2. Si self-hosted et besoin de serverless — SST + OpenNext sur AWS Lambda
  3. Si self-hosted Docker — remplacer fetch par axios où possible, surveiller la RAM, configurer le redémarrage automatique des pods
  4. Si nouveau projet — envisager SvelteKit ou Nuxt comme alternatives sans ce problème

Sources