nextjs - ✅(Solved) Fix Next.js 16.2.2 standalone + Cache Components: cached internal streamed fetches cause unbounded arrayBuffers growth and OOM [1 pull requests, 1 comments, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#92287Fetched 2026-04-08 02:32:37
View on GitHub
Comments
1
Participants
1
Timeline
2
Reactions
0
Author
Participants
Timeline (top)
commented ×1subscribed ×1

Error Message

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

PR fix notes

PR #5510: fix: nextjs high memory usage

Description (problem / solution / changelog)

<br/> <div align="center"> <img src="https://homarr.dev/img/logo.png" height="80" alt="" /> <h3>Homarr</h3> </div>

Thank you for your contribution. Please ensure that your pull request meets the following pull request:

  • Builds without warnings or errors (pnpm build, autofix with pnpm format:fix)
  • Pull request targets dev branch
  • Commits follow the conventional commits guideline
  • No shorthand variable names are used (eg. x, y, i or any abbrevation)
  • Documentation is up to date. Create a pull request here.

Multiple issues idenfitied and tested locally:

https://github.com/vercel/next.js/issues/89091 - The retainer chain was traced by a community member — when compression is enabled and a client disconnects mid-stream, the ServerResponse is held alive by AfterContext closures that reference the zlib Gzip instance. The socket never gets closed, sits in CLOSE-WAIT, and the native zlib buffers leak.

Setting compress: false eliminates that entire retention path. Multiple reporters on the issue confirmed it resolved their memory growth. The trade-off is that responses won't be gzip'd by Next.js. If you ever put this behind a reverse proxy (nginx), that handles compression instead.

https://github.com/vercel/next.js/issues/89091 https://github.com/vercel/next.js/issues/92287 - The httpBatchStreamLink vs httpBatchLink swap isn't tied to a single GitHub issue — it's the general recommendation from the tRPC community and multiple reporters on vercel/next.js#89091 and vercel/next.js#92287. The reasoning is straightforward: httpBatchStreamLink opens a long-lived streaming HTTP response that the client may abandon (page navigation, refresh), leaving the server-side socket in CLOSE-WAIT. httpBatchLink sends a single atomic response — the connection completes before the client can abandon it.

custom socket-cleanup-cjs to cleanup CLOSE_WAIT sockets after 60 seconds.

reproducible in original dev branch with constant refreshing of homarr homepage with multiple apps, rss feeds and plex integration:

ss -tnp | grep ":3000" | awk '{print $1}' | sort | uniq -c | sort -rn # check for connection states
ps aux | grep -E 'tasks\.cjs|wssServer|next-server' | grep -v grep #check RSS for homarr apps

Changed files

  • .gitignore (modified, +5/-1)
  • apps/nextjs/next.config.ts (modified, +1/-0)
  • apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx (modified, +2/-2)
  • nginx.conf (modified, +6/-0)
  • scripts/run.sh (modified, +1/-1)

Code Example

npm install

---

npm run build

---

PORT=3025 npm run start:standalone

---

BASE_URL=http://127.0.0.1:3025 \
DURATION_MS=180000 \
CONCURRENCY=64 \
PAGE_WEIGHT_KB=2048 \
API_WEIGHT_KB=2048 \
MIX=page,api,page,page \
MAX_LOGGED_FAILURES=20 \
npm run load

---

curl 'http://127.0.0.1:3025/api/health?sample=1'

---

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

---

Operating System:
  macOS 15.x arm64
Node.js version:
  25.1.0
Next.js version:
  16.2.2
Output mode:
  standalone
Other config:
  cacheComponents: true
  compress: false
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/mdotk/next-standalone-memory-repro

To Reproduce

  1. Clone the repro repo and install dependencies.
npm install
  1. Build the app.
npm run build
  1. Start the standalone server.
PORT=3025 npm run start:standalone
  1. In another shell, run the reproducing load.
BASE_URL=http://127.0.0.1:3025 \
DURATION_MS=180000 \
CONCURRENCY=64 \
PAGE_WEIGHT_KB=2048 \
API_WEIGHT_KB=2048 \
MIX=page,api,page,page \
MAX_LOGGED_FAILURES=20 \
npm run load
  1. Sample memory during the run.
curl 'http://127.0.0.1:3025/api/health?sample=1'

Current vs. Expected behavior

Current:

On [email protected] with output: "standalone" and cacheComponents: true, the standalone server shows rapid unbounded memory growth under sustained high-cardinality traffic once the app is doing cached internal server-side fetch() calls against a streamed JSON route.

In one local run:

  • baseline was about 95 MB rss
  • after ~28s, memory reached about 1.58 GB rss / 589 MB arrayBuffers
  • after ~38s, memory reached about 2.36 GB rss / 1.04 GB arrayBuffers
  • after ~62s, memory reached about 2.42 GB rss / 1.95 GB arrayBuffers
  • after ~180s, memory reached about 3.43 GB rss / 4.31 GB arrayBuffers

The standalone server then died with:

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

While the server is destabilizing, the load generator starts receiving:

  • ECONNRESET
  • UND_ERR_SOCKET
  • ECONNREFUSED

Expected:

Memory should stabilize or at least be reclaimed after responses complete. Large temporary spikes under load are one thing, but the standalone process should not continue retaining arrayBuffers/external memory until it exits with OOM.

Provide environment information

Operating System:
  macOS 15.x arm64
Node.js version:
  25.1.0
Next.js version:
  16.2.2
Output mode:
  standalone
Other config:
  cacheComponents: true
  compress: false

Additional context

A few things make this feel close to the existing response-retention / runtime-retention family:

  • the failing repro requires cached internal server-side fetch()
  • the internal fetched route returns a streamed JSON response
  • the exploding categories are rss, external, and especially arrayBuffers
  • the app is generating many unique request paths over time

I also ran the same repro app locally with next start as a control. I know that is not the supported way to run an app configured with output: "standalone", so I am not presenting it as the main repro. But it is useful signal:

  • with next start, the app still showed large temporary growth under the same load
  • after the shorter control run stopped, memory recovered back down instead of the server dying
  • with the standalone server, the same app kept climbing and eventually exited with OOM

That difference made me file this specifically against the standalone runtime path.

This also overlaps with symptoms in:

  • #90433
  • #90895
  • #90898
  • #75994

extent analysis

TL;DR

The most likely fix involves addressing the memory leak caused by cached internal server-side fetch() calls against a streamed JSON route in the standalone server.

Guidance

  • Investigate the cacheComponents: true configuration and its impact on memory usage, as it may be contributing to the memory leak.
  • Review the implementation of the streamed JSON response route to ensure that it is properly handling and releasing resources.
  • Consider adding monitoring and logging to track memory usage and identify potential bottlenecks in the application.
  • Look into the existing issues (#90433, #90895, #90898, #75994) for potential solutions or workarounds that may apply to this specific problem.

Example

No specific code snippet can be provided without further information, but reviewing the next-standalone-memory-repro repository may yield insights into the issue.

Notes

The problem seems to be specific to the standalone server and may be related to the way it handles cached components and streamed responses. The fact that the memory recovers when running with next start suggests that the issue may be related to the standalone runtime.

Recommendation

Apply a workaround by disabling cacheComponents or modifying the streamed JSON response route to release resources properly, as the root cause of the issue is likely related to these components.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

nextjs - ✅(Solved) Fix Next.js 16.2.2 standalone + Cache Components: cached internal streamed fetches cause unbounded arrayBuffers growth and OOM [1 pull requests, 1 comments, 1 participants]