Skip to main content
Tilbake til bloggen
Next.jsMemory LeakDockerAWS LambdaNode.js

Next.js Memory Leak: Fetch + Standalone-modus — 2 år uten fiks

Next.js patcher den globale fetch og legger til et cache-lag som lekker minne ved hver forespørsel. I Docker/K8s fører dette til OOM-krasj hver par timer. Buggen har eksistert siden Next.js 14 og er fortsatt uløst i 16.2.x.

Publisert 19. mars 2026Oppdatert 10. august 202610 min lesing
Oppdatering (august 2026): Det lot seg faktisk fikse — konklusjonen nedenfor om at en fiks var «urealistisk», var feil. Årsaken ble funnet i PR #88577: Next.js gjør tee() på fetch-responsstrømmen for å cache den, men registrerte bare én av de to grenene for opprydding, så den andre ble aldri frigjort. Begge klonede bodyer går nå gjennom FinalizationRegistry, sammen med en fiks for LRU-eviction med størrelse 0 (#89040). Merget i canary tidlig i 2026, backportet til stable og med i Next.js 16.3. Hvis du self-hoster med output: standalone, oppgrader til 16.3+ og test på nytt før du fjerner løsningene nedenfor. (Andre lekkasjer — RSC-rendertre-retensjon, Bun — var separate oppfølginger.)

TL;DR

Next.js patcher den globale fetch og legger til et cache-lag som holder referanser til responsdata etter at de burde ha blitt frigjort. Hvert fetch-kall legger til minne som aldri returneres til GC. I Docker/Kubernetes fører dette til OOM-krasj hver par timer. Buggen har eksistert siden Next.js 14 (april 2024) og er fortsatt uløst i 16.2.x (mars 2026). På Vercel viser ikke problemet seg takket være efemere serverless-funksjoner.

Hvordan normal fetch fungerer

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

Hvordan fetch fungerer i Next.js

Next.js fanger opp den globale fetch og pakker den inn med sitt eget cache-/tracking-lag:

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

Hva som skjer i produksjon

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

Berørte versjoner

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

Testet på Node.js 20, 22, 24, 25 — lekker på alle.

Hva som ikke fungerer

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)

Hva som fungerer (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

Begrensning med axios-workaround

Dine egne API-kall kan erstattes med axios. Men Next.js bruker internt den patchede fetch for:

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

Selv uten en eneste fetch i koden din — bruker Next.js den fortsatt internt.

Hvorfor Vercel ikke fikser det

Forretningslogikk

Vercel er et selskap som tjener penger på å hoste Next.js. På deres plattform viser ikke problemet seg (serverless = efemert). Buggen påvirker bare self-hosted (Docker, K8s, VPS) — de som ikke betaler Vercel.

Offisiell posisjon

Tim Neutkens (Vercel-maintainer) analyserte problemet og erklærte at det er et undici-problem (Node.js fetch-bibliotek), ikke Next.js. Issue #90433 ble stengt. Til tross for at:

  • axios og node-fetch på samme Node.js fungerer uten lekkasjer
  • Lekkasjen bare oppstår når fetch går gjennom Next.js-wrapperen
  • Buggen har vært åpen i 2 år uten fiks

Prioriteringer

I løpet av disse 2 årene har Next.js-teamet sluppet:

  • Turbopack (2-5x raskere builds) — markedsføringsfordel
  • Cache Components / use cache — reduserer belastningen på Vercel-servere
  • proxy.ts i stedet for middleware — forenkler edge-deployment på Vercel
  • DevTools MCP — AI-hype

Memory leak i self-hosted? Ikke en prioritet.

Løsning: AWS Lambda (SST + OpenNext)

Hva er det

OpenNext er en open-source-adapter som konverterer en Next.js-build til et format for AWS Lambda. SST er et rammeverk som automatiserer infrastrukturen.

Arkitektur

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

Hvorfor dette løser minneslekkasjen

Lambda-funksjoner behandler forespørsler og resirkuleres etter 5-15 minutters inaktivitet. Minnet rekker ikke å akkumuleres.

Deployment

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

Sammenligning

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ørste forespørsel er tregere (~200-500ms)
  • Sikkerhet — aktiver OAC (Origin Access Control), ellers er Lambda-URL-en offentlig
  • OpenNext — community-prosjekt, ikke offisielt fra Vercel. Nye Next.js-funksjoner kan gå i stykker
  • Lommebokattack — ved DDoS kan Lambda auto-scaling føre til en stor regning

Hvorfor en ekte fiks er urealistisk

1. Arkitekturproblem

Lekkasjen er ikke en tilfeldig bug, men en konsekvens av en designbeslutning: Next.js fanger opp den globale fetch og legger til cache/tracking oppå. For å fikse det må måten App Router interagerer med fetch redesignes. Dette påvirker ISR, revalidation, data cache, request deduplication — kjernen i rammeverket.

2. Interessekonflikt

Vercel er ikke motivert til å fikse det som ikke påvirker deres plattform. Self-hosted konkurrerer med deres forretning. Jo flere problemer i self-hosted — jo flere migrerer til Vercel.

3. Skyldforskyvning

Den offisielle posisjonen er "det er undici, ikke oss". Inntil det endrer seg — vil de ikke jobbe med en fiks.

4. Ingen community-fiks

Next.js AGPL-3.0-lisens tillater forks, men kodebasen er enorm og tett koblet til Vercel-infrastrukturen. En community-PR for å fikse fetch-wrapperen ville kreve dyp forståelse av den interne arkitekturen og godkjenning fra maintainers — som allerede har stengt issuen.

Konklusjoner

  1. Hvis du er på Vercel — ikke noe problem, ingenting å gjøre
  2. Hvis self-hosted og trenger serverless — SST + OpenNext på AWS Lambda
  3. Hvis self-hosted Docker — erstatt fetch med axios der det er mulig, overvåk RAM, konfigurer automatisk pod-omstart
  4. Hvis du starter et nytt prosjekt — vurder SvelteKit eller Nuxt som alternativer uten dette problemet

Kilder

Fant du en feil?

Et feil faktum, en skjev oversettelse, noe som virker usant i denne artikkelen? Skriv til meg — på ditt eget språk.