Skip to main content
← Zurück zum Blog
Next.jsMemory LeakDockerAWS LambdaNode.js

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.

Veröffentlicht 19. März 202610 Min. Lesezeit

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 free

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

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

Betroffene Versionen

Next.js — Alle Versionen mit 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

Getestet auf Node.js 20, 22, 24, 25 — leckt auf allen.

Was nicht funktioniert

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)

Was funktioniert (Workarounds)

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

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.ts statt 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 production

Vergleich

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

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

  1. Auf Vercel — kein Problem, nichts zu tun
  2. Self-Hosted mit Serverless-Bedarf — SST + OpenNext auf AWS Lambda
  3. Self-Hosted Docker — fetch durch axios ersetzen wo möglich, RAM überwachen, automatische Pod-Neustarts einrichten
  4. Neues Projekt — SvelteKit oder Nuxt als Alternative ohne dieses Problem erwägen

Quellen