Link to the code that reproduces this issue
https://github.com/berry95/next-timeout-resource-leak-repro
To Reproduce
- Clone the reproduction repository.
- Install dependencies with
pnpm install.
- Build the standalone server with
pnpm build.
- Start the standalone server with
pnpm start:standalone.
- In another terminal, run
pnpm load.
- Observe the reported server heap usage over repeated requests.
The reproduction sends requests to /api/heap?timeouts=500. The Pages Router
middleware.ts schedules one-shot setTimeout(() => {}, 0) callbacks before
the request reaches the API route. The timeout ids are not retained by user code
and clearTimeout() is not called, matching common fire-and-forget timeout
usage.
The timeouts query parameter intentionally amplifies the issue so retained
sandbox timeout resources are easier to observe locally.
Current vs. Expected behavior
Current behavior:
Naturally completed one-shot timeouts are cleared at the underlying Node timer
level, but their numeric ids remain tracked by Next.js's sandbox
TimeoutsManager. The ids are removed only if user code explicitly calls
clearTimeout(id), or when the whole sandbox module context is cleared.
In a long-lived standalone/self-hosted server process, repeated middleware
requests can therefore make the tracked timeout resources grow monotonically.
The production symptom is step-like heap growth over time and, under sustained
traffic, possible OOM.
Expected behavior:
After a one-shot timeout callback runs, the timeout id should be released from
Next.js's sandbox resource manager even when user code does not explicitly call
clearTimeout(id).
Provide environment information
Operating System:
Platform: win32
Arch: x64
Version: Windows
Binaries:
Node: 24.14.1
npm: 11.11.0
pnpm: 10.33.0
Relevant Packages:
next: 16.3.0-canary.50
react: 19.2.7
react-dom: 19.2.7
typescript: 5.9.3
Next.js Config:
output: standalone
Which area(s) are affected? (Select all that apply)
Middleware, Pages Router, Runtime, Output, Performance
Which stage(s) are affected? (Select all that apply)
next build (local), Other (Deployed)
Additional context
The sandbox resource managers were introduced in #57235 to avoid retaining old
Edge runtime VM contexts during dev HMR by taking ownership of timers and
clearing them when a module context is invalidated. That teardown path is still
needed.
The missing path is natural completion while the module context remains alive:
one-shot timeout callbacks can finish successfully without releasing their ids
from the sandbox manager.
The existing clearTimeout(timeout) inside webSetTimeoutPolyfill works around
the Node.js primitive timer leak described in nodejs/node#53335, but it does not
remove the id from Next.js's own resource manager.
Link to the code that reproduces this issue
https://github.com/berry95/next-timeout-resource-leak-repro
To Reproduce
pnpm install.pnpm build.pnpm start:standalone.pnpm load.The reproduction sends requests to
/api/heap?timeouts=500. The Pages Routermiddleware.tsschedules one-shotsetTimeout(() => {}, 0)callbacks beforethe request reaches the API route. The timeout ids are not retained by user code
and
clearTimeout()is not called, matching common fire-and-forget timeoutusage.
The
timeoutsquery parameter intentionally amplifies the issue so retainedsandbox timeout resources are easier to observe locally.
Current vs. Expected behavior
Current behavior:
Naturally completed one-shot timeouts are cleared at the underlying Node timer
level, but their numeric ids remain tracked by Next.js's sandbox
TimeoutsManager. The ids are removed only if user code explicitly callsclearTimeout(id), or when the whole sandbox module context is cleared.In a long-lived standalone/self-hosted server process, repeated middleware
requests can therefore make the tracked timeout resources grow monotonically.
The production symptom is step-like heap growth over time and, under sustained
traffic, possible OOM.
Expected behavior:
After a one-shot timeout callback runs, the timeout id should be released from
Next.js's sandbox resource manager even when user code does not explicitly call
clearTimeout(id).Provide environment information
Which area(s) are affected? (Select all that apply)
Middleware, Pages Router, Runtime, Output, Performance
Which stage(s) are affected? (Select all that apply)
next build (local), Other (Deployed)
Additional context
The sandbox resource managers were introduced in #57235 to avoid retaining old
Edge runtime VM contexts during dev HMR by taking ownership of timers and
clearing them when a module context is invalidated. That teardown path is still
needed.
The missing path is natural completion while the module context remains alive:
one-shot timeout callbacks can finish successfully without releasing their ids
from the sandbox manager.
The existing
clearTimeout(timeout)insidewebSetTimeoutPolyfillworks aroundthe Node.js primitive timer leak described in nodejs/node#53335, but it does not
remove the id from Next.js's own resource manager.