Skip to main content
Tillbaka till bloggen
Next.jsMemory LeakDockerAWS LambdaNode.js

Next.js Memory Leak: Fetch + Standalone-läge — 2 år utan fix

Next.js patchar den globala fetch och lägger till ett cache-lager som läcker minne vid varje förfrågan. I Docker/K8s leder detta till OOM-krascher var några timmar. Buggen har funnits sedan Next.js 14 och är fortfarande olöst i 16.2.x.

Publicerad 19 mars 2026Uppdaterad 10 augusti 202610 min läsning
Uppdatering (augusti 2026): Det gick faktiskt att fixa — slutsatsen nedan om att en fix vore "orealistisk" var fel. Grundorsaken hittades i PR #88577: Next.js gör tee() på fetch-svarets ström för att cacha den, men registrerade bara en av de två grenarna för uppstädning, så den andra frigjordes aldrig. Båda klonade bodies går nu via FinalizationRegistry, tillsammans med en fix för LRU-eviction med storlek 0 (#89040). Mergat i canary i början av 2026, backportat till stable och med i Next.js 16.3. Om du kör self-host med output: standalone, uppgradera till 16.3+ och testa om innan du tar bort lösningarna nedan. (Andra läckor — RSC-renderträds-retention, Bun — var separata uppföljningar.)

TL;DR

Next.js patchar den globala fetch och lägger till ett cache-lager som håller referenser till svarsdata efter att de borde ha frigjorts. Varje fetch-anrop lägger till minne som aldrig returneras till GC. I Docker/Kubernetes leder detta till OOM-krascher var några timmar. Buggen har funnits sedan Next.js 14 (april 2024) och är fortfarande olöst i 16.2.x (mars 2026). På Vercel visar sig problemet inte tack vare efemära serverless-funktioner.

Hur normal fetch fungerar

Request → fetch → got data → response to user → GC cleans up → memory free

Hur fetch fungerar i Next.js

Next.js fångar upp den globala fetch och omsluter den med sitt eget cache-/tracking-lager:

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

Vad som händer i produktion

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

Drabbade versioner

Next.js — Alla versioner med 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

Testat på Node.js 20, 22, 24, 25 — läcker på alla.

Vad som inte fungerar

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)

Vad som fungerar (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

Begränsning med axios-workaround

Dina egna API-anrop kan ersättas med axios. Men Next.js använder internt den patchade fetch för:

  • ISR (Incremental Static Regeneration)
  • revalidatePath / revalidateTag
  • Server Components data fetching med deduplicering
  • use cache (Next.js 16)

Även utan en enda fetch i din kod — använder Next.js det fortfarande internt.

Varför Vercel inte fixar det

Affärslogik

Vercel är ett företag som tjänar pengar på att hosta Next.js. På deras plattform visar sig problemet inte (serverless = efemärt). Buggen påverkar bara self-hosted (Docker, K8s, VPS) — de som inte betalar Vercel.

Officiell position

Tim Neutkens (Vercel-maintainer) analyserade problemet och förklarade att det är ett undici-problem (Node.js fetch-bibliotek), inte Next.js. Issue #90433 stängdes. Trots att:

  • axios och node-fetch på samma Node.js fungerar utan läckor
  • Läckan bara uppstår när fetch går genom Next.js-wrappern
  • Buggen har varit öppen i 2 år utan fix

Prioriteringar

Under dessa 2 år har Next.js-teamet släppt:

  • Turbopack (2-5x snabbare builds) — marknadsföringsfördel
  • Cache Components / use cache — minskar belastningen på Vercel-servrar
  • proxy.ts istället för middleware — förenklar edge-deployment på Vercel
  • DevTools MCP — AI-hype

Memory leak i self-hosted? Inte en prioritet.

Lösning: AWS Lambda (SST + OpenNext)

Vad är det

OpenNext är en open-source-adapter som konverterar en Next.js-build till ett format för AWS Lambda. SST är ett ramverk som automatiserar infrastrukturen.

Arkitektur

Next.js build
  → OpenNext
    → AWS Lambda (SSR, API routes)
    → S3 (static, assets)
    → CloudFront (CDN)
    → SQS + DynamoDB (ISR revalidation)

Varför detta löser minnesläckan

Lambda-funktioner bearbetar förfrågningar och återvinns efter 5-15 minuters inaktivitet. Minnet hinner inte ackumuleras.

Deployment

npx sst@latest init
npx sst deploy --stage production

Jämförelse

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-nyanser

  • Cold starts — första förfrågan är långsammare (~200-500ms)
  • Säkerhet — aktivera OAC (Origin Access Control), annars är Lambda-URL:en publik
  • OpenNext — community-projekt, inte officiellt från Vercel. Nya Next.js-funktioner kan gå sönder
  • Plånboksattack — vid DDoS kan Lambda auto-scaling leda till en stor faktura

Varför en riktig fix är orealistisk

1. Arkitekturproblem

Läckan är inte en slumpmässig bugg utan en konsekvens av ett designbeslut: Next.js fångar upp den globala fetch och lägger till cache/tracking ovanpå. För att fixa det behöver sättet App Router interagerar med fetch designas om. Detta påverkar ISR, revalidation, data cache, request deduplication — ramverkets kärna.

2. Intressekonflikt

Vercel är inte motiverat att fixa det som inte påverkar deras plattform. Self-hosted konkurrerar med deras affär. Ju fler problem i self-hosted — desto fler migrerar till Vercel.

3. Skuldförskjutning

Den officiella positionen är "det är undici, inte vi". Tills det ändras — kommer de inte arbeta på en fix.

4. Ingen community-fix

Next.js AGPL-3.0-licens tillåter forks, men kodbasen är enorm och tätt kopplad till Vercel-infrastrukturen. En community-PR för att fixa fetch-wrappern skulle kräva djup förståelse av den interna arkitekturen och godkännande från maintainers — som redan stängt issuen.

Slutsatser

  1. Om du är på Vercel — inget problem, inget att göra
  2. Om self-hosted och behöver serverless — SST + OpenNext på AWS Lambda
  3. Om self-hosted Docker — ersätt fetch med axios där det är möjligt, övervaka RAM, konfigurera automatisk pod-omstart
  4. Om du startar ett nytt projekt — överväg SvelteKit eller Nuxt som alternativ utan detta problem

Källor

Hittade du ett fel?

Ett felaktigt faktum, en skev översättning, något som känns falskt i den här artikeln? Skriv till mig — på ditt eget språk.