Next.js Memory Leak: Fetch + Standalone-Modus — 2 Jahre ohne Fix
Next.js patcht den globalen fetch und fügt eine Cache-Schicht hinzu, die bei jeder Anfrage Speicher verliert. In Docker/K8s führt dies alle paar Stunden zu OOM-Crashes. Der Bug existiert seit Next.js 14 und ist in 16.2.x noch ungelöst.
TL;DR
Next.js patcht den globalen fetch und fügt eine Cache-Schicht hinzu, die Referenzen auf Response-Daten hält, nachdem sie freigegeben werden sollten. Jeder fetch-Aufruf fügt Speicher hinzu, der nie vom GC zurückgegeben wird. In Docker/Kubernetes führt dies alle paar Stunden zu OOM-Crashes. Der Bug existiert seit Next.js 14 (April 2024) und ist in 16.2.x (März 2026) noch ungelöst. Auf Vercel tritt das Problem dank ephemerer Serverless-Funktionen nicht auf.
Wie normaler Fetch funktioniert
Request → fetch → got data → response to user → GC cleans up → memory freeWie Fetch in Next.js funktioniert
Next.js fängt den globalen fetch ab und umhüllt ihn mit einer eigenen Cache-/Tracking-Schicht:
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 indefinitelyWas in Produktion passiert
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 accumulatesBetroffene Versionen
Next.js — Alle Versionen mit 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
Getestet auf Node.js 20, 22, 24, 25 — leckt auf allen.
Was nicht funktioniert
| 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) |
Was funktioniert (Workarounds)
| 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 |
Einschränkung des Axios-Workarounds
Eigene API-Aufrufe können durch axios ersetzt werden. Aber Next.js verwendet intern den gepatchten fetch für:
- ISR (Incremental Static Regeneration)
revalidatePath/revalidateTag- Server Components Data Fetching mit Deduplizierung
use cache(Next.js 16)
Selbst ohne einen einzigen fetch im eigenen Code — Next.js verwendet ihn intern weiterhin.
Warum Vercel es nicht fixt
Geschäftslogik
Vercel verdient Geld mit dem Hosting von Next.js. Auf ihrer Plattform tritt das Problem nicht auf (serverless = ephemeral). Der Bug betrifft nur Self-Hosted (Docker, K8s, VPS) — also die, die nicht an Vercel zahlen.
Offizielle Position
Tim Neutkens (Vercel-Maintainer) analysierte das Problem und erklärte es zum undici-Problem (Node.js-Fetch-Bibliothek), nicht Next.js. Issue #90433 wurde geschlossen. Obwohl:
- axios und node-fetch auf demselben Node.js ohne Leaks funktionieren
- Das Leak nur auftritt, wenn fetch durch den Next.js-Wrapper geht
- Der Bug seit 2 Jahren ohne Fix offen ist
Prioritäten
In diesen 2 Jahren hat das Next.js-Team veröffentlicht:
- Turbopack (2-5x schnellere Builds) — Marketingvorteil
- Cache Components /
use cache— reduziert Last auf Vercel-Servern proxy.tsstatt Middleware — vereinfacht Edge-Deployment auf Vercel- DevTools MCP — AI-Hype
Memory Leak bei Self-Hosted? Keine Priorität.
Lösung: AWS Lambda (SST + OpenNext)
Was ist das
OpenNext ist ein Open-Source-Adapter, der einen Next.js-Build in ein AWS-Lambda-Format konvertiert. SST ist ein Framework zur Automatisierung der Infrastruktur.
Architektur
Next.js build
→ OpenNext
→ AWS Lambda (SSR, API routes)
→ S3 (static, assets)
→ CloudFront (CDN)
→ SQS + DynamoDB (ISR revalidation)Warum dies das Memory Leak löst
Lambda-Funktionen verarbeiten Anfragen und werden nach 5-15 Minuten Inaktivität recycelt. Speicher hat keine Zeit sich anzusammeln.
Deployment
npx sst@latest init
npx sst deploy --stage productionVergleich
| 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 |
Lambda-Nuancen
- Cold Starts — erste Anfrage ist langsamer (~200-500ms)
- Sicherheit — OAC (Origin Access Control) aktivieren, sonst ist die Lambda-URL öffentlich
- OpenNext — Community-Projekt, nicht offiziell von Vercel. Neue Next.js-Features können brechen
- Wallet-Attacke — bei DDoS kann Lambda-Auto-Scaling zu einer hohen Rechnung führen
Warum ein echter Fix unrealistisch ist
1. Architekturproblem
Das Leak ist kein zufälliger Bug, sondern Folge einer Design-Entscheidung: Next.js fängt den globalen fetch ab und fügt Cache/Tracking darüber hinzu. Um es zu fixen, müsste die Art, wie App Router mit fetch interagiert, neu designed werden. Das betrifft ISR, Revalidation, Data Cache, Request Deduplication — den Kern des Frameworks.
2. Interessenkonflikt
Vercel ist nicht motiviert zu fixen, was ihre Plattform nicht betrifft. Self-Hosted konkurriert mit ihrem Geschäft. Je mehr Probleme bei Self-Hosted — desto mehr Menschen migrieren zu Vercel.
3. Blame Shifting
Die offizielle Position lautet "es ist undici, nicht wir". Solange sich das nicht ändert, wird nicht an einem Fix gearbeitet.
4. Kein Community Fix
Die AGPL-3.0-Lizenz von Next.js erlaubt Forks, aber die Codebasis ist riesig und eng mit der Vercel-Infrastruktur gekoppelt. Ein Community-PR zum Fixen des Fetch-Wrappers würde tiefes Verständnis der internen Architektur und Zustimmung der Maintainer erfordern — die das Issue bereits geschlossen haben.
Schlussfolgerungen
- Auf Vercel — kein Problem, nichts zu tun
- Self-Hosted mit Serverless-Bedarf — SST + OpenNext auf AWS Lambda
- Self-Hosted Docker — fetch durch axios ersetzen wo möglich, RAM überwachen, automatische Pod-Neustarts einrichten
- Neues Projekt — SvelteKit oder Nuxt als Alternative ohne dieses Problem erwägen
Quellen
- 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