Skip to main content
Înapoi la blog
Next.jsMemory LeakDockerAWS LambdaNode.js

Next.js Memory Leak: Fetch + Mod Standalone — 2 ani fără rezolvare

Next.js aplică un patch peste fetch-ul global și adaugă un strat de cache care pierde memorie la fiecare cerere. În Docker/K8s asta provoacă crash-uri OOM la fiecare câteva ore. Bug-ul există din Next.js 14 și rămâne nerezolvat în 16.2.x.

Publicat 19 martie 202610 min de citit

TL;DR

Next.js aplică un patch peste fetch-ul global și adaugă un strat de cache care păstrează referințe către datele de răspuns după ce ar fi trebuit eliberate. Fiecare apel fetch adaugă memorie care nu este niciodată returnată către GC. În Docker/Kubernetes acest lucru duce la crash-uri OOM la fiecare câteva ore. Bug-ul există din Next.js 14 (aprilie 2024) și rămâne nerezolvat în 16.2.x (martie 2026). Pe Vercel problema nu se manifestă datorită funcțiilor serverless efemere.

Cum funcționează un fetch normal

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

Cum funcționează fetch în Next.js

Next.js interceptează fetch-ul global și îl împachetează cu propriul strat de cache/tracking:

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

Ce se întâmplă în producție

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

Versiuni afectate

Next.js — Toate versiunile cu 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 pe Node.js 20, 22, 24, 25 — pierde memorie pe toate.

Ce nu funcționează

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)

Ce funcționează (workaround-uri)

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

Limitarea workaround-ului cu axios

Propriile apeluri API pot fi înlocuite cu axios. Dar Next.js folosește intern fetch-ul modificat pentru:

  • ISR (Incremental Static Regeneration)
  • revalidatePath / revalidateTag
  • Preluarea datelor în Server Components cu deduplicare
  • use cache (Next.js 16)

Chiar și fără un singur fetch în codul tău — Next.js îl folosește tot intern.

De ce Vercel nu rezolvă problema

Logica de business

Vercel este o companie care câștigă bani din găzduirea Next.js. Pe platforma lor problema nu se manifestă (serverless = efemer). Bug-ul afectează doar self-hosted (Docker, K8s, VPS) — adică pe cei care nu plătesc Vercel.

Poziția oficială

Tim Neutkens (maintainer Vercel) a analizat problema și a declarat că este o problemă de undici (biblioteca fetch din Node.js), nu de Next.js. Issue-ul #90433 a fost închis. În ciuda faptului că:

  • axios și node-fetch pe același Node.js funcționează fără scurgeri
  • Scurgerea apare doar când fetch trece prin wrapper-ul Next.js
  • Bug-ul este deschis de 2 ani fără o rezolvare

Priorități

În acești 2 ani echipa Next.js a livrat:

  • Turbopack (build-uri de 2-5x mai rapide) — avantaj de marketing
  • Cache Components / use cache — reduce încărcarea pe serverele Vercel
  • proxy.ts în locul middleware-ului — simplifică deployment-ul edge pe Vercel
  • DevTools MCP — hype-ul AI

Memory leak în self-hosted? Nu e o prioritate.

Soluția: AWS Lambda (SST + OpenNext)

Ce este

OpenNext este un adaptor open-source care convertește un build Next.js într-un format pentru AWS Lambda. SST este un framework care automatizează infrastructura.

Arhitectură

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

De ce asta rezolvă memory leak-ul

Funcțiile Lambda procesează cererile și sunt reciclate după 5-15 minute de inactivitate. Memoria nu apucă să se acumuleze.

Deployment

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

Comparație

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

Nuanțe Lambda

  • Cold starts — prima cerere este mai lentă (~200-500ms)
  • Securitate — activează OAC (Origin Access Control), altfel URL-ul Lambda este public
  • OpenNext — proiect comunitar, nu oficial Vercel. Funcțiile noi din Next.js se pot strica
  • Atac asupra portofelului — în timpul unui DDoS, auto-scaling-ul Lambda poate genera o factură mare

De ce o rezolvare reală este nerealistă

1. Problemă arhitecturală

Scurgerea nu este un bug accidental, ci consecința unei decizii de design: Next.js interceptează fetch-ul global și adaugă cache/tracking peste el. Ca să o repari — trebuie regândit modul în care App Router interacționează cu fetch. Asta afectează ISR, revalidation, data cache, request deduplication — nucleul framework-ului.

2. Conflict de interese

Vercel nu este motivat să repare ceva ce nu le afectează platforma. Self-hosted concurează cu business-ul lor. Cu cât sunt mai multe probleme în self-hosted — cu atât mai mulți oameni migrează pe Vercel.

3. Pasarea vinei

Poziția oficială este "e undici, nu noi". Până când asta nu se schimbă — nu vor lucra la o rezolvare.

4. Nicio rezolvare din comunitate

Licența AGPL-3.0 a Next.js permite fork-uri, dar codebase-ul este uriaș și strâns cuplat cu infrastructura Vercel. Un PR din comunitate pentru a repara wrapper-ul fetch ar necesita o înțelegere profundă a arhitecturii interne și aprobarea maintainerilor — care au închis deja issue-ul.

Concluzii

  1. Dacă ești pe Vercel — nicio problemă, nu ai ce face
  2. Dacă ești self-hosted și ai nevoie de serverless — SST + OpenNext pe AWS Lambda
  3. Dacă ești self-hosted Docker — înlocuiește fetch cu axios unde se poate, monitorizează RAM-ul, configurează restart automat al pod-urilor
  4. Dacă începi un proiect nou — ia în calcul SvelteKit sau Nuxt ca alternative fără această problemă

Surse