Skip to content

fix: close the RSC streams Next.js leaves open when it prerenders a page - #1456

Open
donfear wants to merge 2 commits into
opennextjs:mainfrom
donfear:fix/close-unclosed-rsc-streams
Open

donfear wants to merge 2 commits into
opennextjs:mainfrom
donfear:fix/close-unclosed-rsc-streams

Conversation

@donfear

@donfear donfear commented Oct 15, 2026 •

Copy link
Copy Markdown

Fixes #1455

Problem

When Next.js prerenders an App Router page it builds three ReadableStreams that it never closes: createUnclosingStream in the app-page runtime, and createUnclosingPrefetchStream plus the inline pageDataStream (16.4+) in collect-segment-data. Next.js relies on garbage collection to reclaim them. On workerd the data they carried stays reachable, so every page prerendered at runtime (on-demand ISR and revalidation) retains about its RSC payload: ~1.4 MB per render for a 600 KB page, until the isolate reaches the memory limit. Details and measurements in #1455.

Fix

A new close-rsc-streams patch, registered with the other Cloudflare patches in createServerBundle:

  • app-page*.runtime.prod.js: createUnclosingStream's i<chunks.length&&c.enqueue(chunks[i++]) becomes i<chunks.length?c.enqueue(chunks[i++]):c.close(), the shape of createClosingStream that Next.js ships right next to it. All runtime variants are patched, including -experimental: React's experimental build is also used for taint / viewTransition without PPR.
  • .next/server/chunks/*.js: closes createUnclosingPrefetchStream before its bare return, and the pageDataStream after its last enqueue.

The rules match on the shape of the streams (minified webpack and Turbopack output, and unminified output), and each one skips a stream that already closes, so apps that patched Next.js themselves are not closed twice. The whole patch is skipped when cacheComponents, experimental.ppr or experimental.dynamicIO is enabled, where Next.js needs the streams open.

Version boundary: createUnclosingStream exists since 15.0.0, createUnclosingPrefetchStream since 15.x and pageDataStream since 16.4. Checked against 15.5.28, 16.4.1 and 16.5.0-canary.14.

Verification

  • Spec with fixtures taken from Next.js 16.4.1 (a minified webpack chunk, the compiled runtime and the unminified ESM source), including the no-op cases.
  • The spec also runs the patcher entries: the path filters (runtime variants, webpack and Turbopack chunks, Windows paths), the content filters, and the PPR / cacheComponents skip.
  • examples/playground16/e2e/close-rsc-streams.cloudflare.spec.ts asserts on the built handler.mjs that no unclosed stream is left. It passes with webpack and Turbopack, and fails on an unpatched bundle.
  • examples/e2e/app-router (webpack): the built handler.mjs has no unclosed form left and all three streams close. CI=true pnpm --filter app-router e2e: 70 passed, 3 skipped.
  • examples/e2e/experimental (cacheComponents: true): handler.mjs is unchanged.
  • The repro from [BUG] ISR pages prerendered at runtime retain their RSC payload: Next.js leaves three streams open, ~1.4 MB per render #1455 (Turbopack, stock Next.js 16.4.1) with this branch packed: +2.9 MB of heap after 300 ISR renders, against +401 MB with 1.20.12.
  • pnpm code:checks and pnpm test pass.

Not run: the Turbopack e2e suite (pnpm e2e-turbopack).


Devin Review

@changeset-bot

changeset-bot Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4c0da9a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@opennextjs/cloudflare Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Devin Review: 1 flag

Not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

@vicb

vicb commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

See #1455 (comment)

Let's wait for the feedback on the workerd issue fisrt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] ISR pages prerendered at runtime retain their RSC payload: Next.js leaves three streams open, ~1.4 MB per render

2 participants