Skip to main content
← Назад до блогу
Next.jsMemory LeakDockerAWS LambdaNode.js

Next.js Memory Leak: Fetch + Standalone Mode — 2 роки без фіксу

Next.js патчить глобальний fetch та додає кеш-шар, який тече на кожному запиті. В Docker/K8s це призводить до OOM crash кожні кілька годин. Баг існує з Next.js 14 і досі не вирішений у 16.2.x.

Опубліковано 19 березня 2026 р.10 хв читання

TL;DR

Next.js патчить глобальний fetch та додає кеш-шар, який тримає references на response data після того як вони мали б бути звільнені. Кожен fetch виклик додає пам'яті яка ніколи не повертається GC. В Docker/Kubernetes це призводить до OOM crash кожні кілька годин. Баг існує з Next.js 14 (квітень 2024) і досі не вирішений у 16.2.x (березень 2026). На Vercel проблема не проявляється через ephemeral serverless функції.

Як працює нормальний fetch

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

Як працює fetch у Next.js

Next.js перехоплює глобальний fetch і обгортає його своїм кеш/трекінг шаром:

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

Що відбувається на продакшні

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

Уражені версії

Next.js — всі версії з 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

Тестували на Node.js 20, 22, 24, 25 — на всіх тече.

Що не працює

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)

Що працює (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

Обмеження workaround з axios

Свої API-запити можна замінити на axios. Але Next.js внутрішньо використовує патчений fetch для:

  • ISR (Incremental Static Regeneration)
  • revalidatePath / revalidateTag
  • Server Components data fetching з дедуплікацією
  • use cache (Next.js 16)

Тобто навіть без жодного fetch у своєму коді — Next.js все одно використовує його під капотом.

Чому Vercel не фіксить

Бізнес-логіка

Vercel — компанія яка заробляє на хостингу Next.js. На їхній платформі проблема не проявляється (serverless = ephemeral). Баг зачіпає тільки self-hosted (Docker, K8s, VPS) — тобто тих хто не платить Vercel.

Офіційна позиція

Tim Neutkens (мейнтейнер Vercel) провів аналіз і заявив що це проблема undici (Node.js fetch бібліотека), а не Next.js. Issue #90433 закрили. При тому що:

  • axios і node-fetch на тому ж Node.js працюють без витоків
  • Витік з'являється тільки коли fetch проходить через Next.js обгортку
  • Баг відкритий 2 роки без фіксу

Пріоритети

За ці 2 роки команда Next.js випустила:

  • Turbopack (2-5x швидші білди) — маркетингова перевага
  • Cache Components / use cache — зменшує навантаження на Vercel сервери
  • proxy.ts замість middleware — спрощує edge-деплой на Vercel
  • DevTools MCP — AI-хайп

Memory leak у self-hosted? Не в пріоритетах.

Рішення: AWS Lambda (SST + OpenNext)

Що це

OpenNext — open-source адаптер який перетворює Next.js build у формат для AWS Lambda. SST — фреймворк який автоматизує інфраструктуру.

Архітектура

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

Чому це вирішує memory leak

Lambda функція обробляє запити і recycled через 5-15 хвилин неактивності. Пам'ять не встигає накопитись.

Деплой

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

Порівняння

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

  • Cold starts — перший запит повільніший (~200-500ms)
  • Безпека — увімкнути OAC (Origin Access Control), інакше Lambda URL публічний
  • OpenNext — community проєкт, не офіційний Vercel. Нові фічі Next.js можуть ламатись
  • Wallet attack — при DDoS автоскейлінг Lambda може призвести до великого рахунку

Чому вирішити нереально

1. Архітектурна проблема

Витік — не випадковий баг, а наслідок дизайн-рішення: Next.js перехоплює глобальний fetch і додає кеш/трекінг поверх. Щоб пофіксити — потрібно переробити як App Router взаємодіє з fetch. Це зачіпає ISR, revalidation, data cache, request deduplication — ядро фреймворку.

2. Конфлікт інтересів

Vercel не мотивований фіксити те що не зачіпає їхню платформу. Self-hosted конкурує з їхнім бізнесом. Чим більше проблем у self-hosted — тим більше людей мігрують на Vercel.

3. Blame shifting

Офіційна позиція — "це undici, не ми". Поки вона не зміниться — над фіксом не працюватимуть.

4. Немає community fix

AGPL-3.0 ліцензія Next.js дозволяє форки, але кодова база величезна і тісно зв'язана з Vercel інфраструктурою. Community PR з фіксом fetch обгортки потребував би глибокого розуміння внутрішньої архітектури і схвалення мейнтейнерів — які вже закрили issue.

Висновки

  1. Якщо на Vercel — проблеми немає, не потрібно нічого робити
  2. Якщо self-hosted і потрібен serverless — SST + OpenNext на AWS Lambda
  3. Якщо self-hosted Docker — замінити fetch на axios де можливо, моніторити RAM, налаштувати автоматичний рестарт подів
  4. Якщо починаєш новий проєкт — розглянути SvelteKit або Nuxt як альтернативу без цієї проблеми

Джерела