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.
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 freeHur 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 indefinitelyVad 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 accumulatesDrabbade versioner
Next.js — Alla versioner med 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
Testat på Node.js 20, 22, 24, 25 — läcker på alla.
Vad som inte fungerar
| 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) |
Vad som fungerar (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 |
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.tsistä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 productionJämförelse
| 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-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
- Om du är på Vercel — inget problem, inget att göra
- Om self-hosted och behöver serverless — SST + OpenNext på AWS Lambda
- Om self-hosted Docker — ersätt fetch med axios där det är möjligt, övervaka RAM, konfigurera automatisk pod-omstart
- Om du startar ett nytt projekt — överväg SvelteKit eller Nuxt som alternativ utan detta problem
Källor
- 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
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.