Skip to main content
← Volver al blog
Next.jsMemory LeakDockerAWS LambdaNode.js

Next.js Memory Leak: Fetch + Modo Standalone — 2 años sin solución

Next.js parchea el fetch global y añade una capa de caché que pierde memoria en cada petición. En Docker/K8s esto causa crashes OOM cada pocas horas. El bug existe desde Next.js 14 y sigue sin resolverse en 16.2.x.

Publicado 19 de marzo de 202610 min de lectura

TL;DR

Next.js parchea el fetch global y añade una capa de caché que mantiene referencias a los datos de respuesta después de que deberían haber sido liberados. Cada llamada a fetch añade memoria que nunca es devuelta al GC. En Docker/Kubernetes esto provoca crashes OOM cada pocas horas. El bug existe desde Next.js 14 (abril 2024) y sigue sin resolverse en 16.2.x (marzo 2026). En Vercel el problema no se manifiesta gracias a las funciones serverless efímeras.

Cómo funciona fetch normalmente

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

Cómo funciona fetch en Next.js

Next.js intercepta el fetch global y lo envuelve con su propia capa de caché/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

Qué ocurre en producción

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

Versiones afectadas

Next.js — Todas las versiones con 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

Probado en Node.js 20, 22, 24, 25 — fuga en todos.

Qué no funciona

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)

Qué funciona (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

Limitación del workaround con axios

Tus propias llamadas API pueden reemplazarse con axios. Pero Next.js usa internamente el fetch parcheado para:

  • ISR (Incremental Static Regeneration)
  • revalidatePath / revalidateTag
  • Data fetching de Server Components con deduplicación
  • use cache (Next.js 16)

Incluso sin un solo fetch en tu código — Next.js lo sigue usando internamente.

Por qué Vercel no lo arregla

Lógica de negocio

Vercel es una empresa que gana dinero alojando Next.js. En su plataforma el problema no se manifiesta (serverless = efímero). El bug solo afecta a self-hosted (Docker, K8s, VPS) — los que no pagan a Vercel.

Posición oficial

Tim Neutkens (mantenedor de Vercel) analizó el problema y declaró que es un problema de undici (biblioteca fetch de Node.js), no de Next.js. El issue #90433 fue cerrado. A pesar de que:

  • axios y node-fetch en el mismo Node.js funcionan sin fugas
  • La fuga solo aparece cuando fetch pasa por el wrapper de Next.js
  • El bug lleva 2 años abierto sin solución

Prioridades

En estos 2 años el equipo de Next.js lanzó:

  • Turbopack (builds 2-5x más rápidos) — ventaja de marketing
  • Cache Components / use cache — reduce carga en servidores Vercel
  • proxy.ts en lugar de middleware — simplifica el despliegue edge en Vercel
  • DevTools MCP — hype de IA

¿Memory leak en self-hosted? No es prioridad.

Solución: AWS Lambda (SST + OpenNext)

Qué es

OpenNext es un adaptador open-source que convierte un build de Next.js en formato para AWS Lambda. SST es un framework que automatiza la infraestructura.

Arquitectura

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

Por qué esto resuelve el memory leak

Las funciones Lambda procesan peticiones y se reciclan tras 5-15 minutos de inactividad. La memoria no tiene tiempo de acumularse.

Despliegue

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

Comparación

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

Matices de Lambda

  • Cold starts — la primera petición es más lenta (~200-500ms)
  • Seguridad — activar OAC (Origin Access Control), sino la URL de Lambda es pública
  • OpenNext — proyecto comunitario, no oficial de Vercel. Nuevas funciones de Next.js pueden romperse
  • Ataque al monedero — durante DDoS, el auto-scaling de Lambda puede generar una factura grande

Por qué una solución real es poco realista

1. Problema arquitectónico

La fuga no es un bug accidental sino consecuencia de una decisión de diseño: Next.js intercepta el fetch global y añade caché/tracking encima. Para arreglarlo hay que rediseñar cómo App Router interactúa con fetch. Esto afecta ISR, revalidation, data cache, request deduplication — el núcleo del framework.

2. Conflicto de intereses

Vercel no está motivado a arreglar lo que no afecta su plataforma. Self-hosted compite con su negocio. Cuantos más problemas en self-hosted — más personas migran a Vercel.

3. Echar la culpa

La posición oficial es "es undici, no nosotros". Hasta que eso cambie — no trabajarán en una solución.

4. Sin solución comunitaria

La licencia AGPL-3.0 de Next.js permite forks, pero la base de código es enorme y está estrechamente acoplada con la infraestructura de Vercel. Un PR comunitario para arreglar el wrapper de fetch requeriría un profundo conocimiento de la arquitectura interna y la aprobación de los mantenedores — que ya cerraron el issue.

Conclusiones

  1. Si estás en Vercel — no hay problema, nada que hacer
  2. Si self-hosted y necesitas serverless — SST + OpenNext en AWS Lambda
  3. Si self-hosted Docker — reemplazar fetch con axios donde sea posible, monitorear RAM, configurar reinicios automáticos de pods
  4. Si empiezas un proyecto nuevo — considerar SvelteKit o Nuxt como alternativas sin este problema

Fuentes