Avoid using unclosing prefetch streams in the browser#89610
Merged
unstubbable merged 1 commit intocanaryfrom Feb 9, 2026
Merged
Avoid using unclosing prefetch streams in the browser#89610unstubbable merged 1 commit intocanaryfrom
unstubbable merged 1 commit intocanaryfrom
Conversation
dc3cf74 to
08bd7d0
Compare
Contributor
Tests Passed |
Contributor
Stats from current PR🟢 1 improvement
📊 All Metrics📖 Metrics GlossaryDev Server Metrics:
Build Metrics:
Change Thresholds:
⚡ Dev Server
📦 Dev Server (Webpack) (Legacy)📦 Dev Server (Webpack)
⚡ Production Builds
📦 Production Builds (Webpack) (Legacy)📦 Production Builds (Webpack)
📦 Bundle SizesBundle Sizes⚡ TurbopackClient Main Bundles: **437 kB** → **437 kB** ✅ -41 B81 files with content-based hashes (individual files not comparable between builds) Server Middleware
Build DetailsBuild Manifests
📦 WebpackClient Main Bundles
Polyfills
Pages
Server Edge SSR
Middleware
Build DetailsBuild Manifests
Build Cache
🔄 Shared (bundler-independent)Runtimes
📝 Changed Files (8 files)Files with changes:
View diffsapp-page-exp..ntime.dev.jsDiff too large to display app-page-exp..time.prod.jsfailed to diffapp-page-tur..ntime.dev.jsDiff too large to display app-page-tur..time.prod.jsfailed to diffapp-page-tur..ntime.dev.jsDiff too large to display app-page-tur..time.prod.jsDiff too large to display app-page.runtime.dev.jsDiff too large to display app-page.runtime.prod.jsDiff too large to display |
6777d99 to
bd2abb5
Compare
Previously, `createPrefetchResponseStream` intentionally never called `controller.close()` on the wrapper stream, to prevent React Flight from erroring on unresolved references (PPR dynamic holes). However, Chrome and Firefox keep unclosed ReadableStreams with pending reads as native GC roots, preventing the stream — and the entire FlightResponse captured in the `reader.read().then(progress)` closure chain — from being collected. Now that React Flight supports `unstable_allowPartialStream`, we can close the stream normally. Flight will mark unresolved chunks as "halted" instead of erroring, which is the correct behavior for prefetch responses. Also removes the now-unnecessary `createUnclosingPrefetchStream` wrapper from the legacy prefetch path in `fetch-server-response.ts`.
bd2abb5 to
168b8ff
Compare
acdlite
approved these changes
Feb 9, 2026
unstubbable
added a commit
that referenced
this pull request
Feb 10, 2026
Follow-up to #89610. Adds an e2e test that detects linear heap growth caused by unclosed prefetch response streams. The test cycles through mounting/unmounting links to trigger repeated prefetches and LRU evictions, then uses CDP heap profiling with linear regression to verify the heap plateaus rather than growing steadily.
unstubbable
added a commit
that referenced
this pull request
Feb 10, 2026
…9756) Follow-up to #89610. Adds an e2e test that detects linear heap growth caused by unclosed prefetch response streams. The test cycles through mounting/unmounting links to trigger repeated prefetches and LRU evictions, then uses CDP heap profiling with linear regression to verify the heap plateaus rather than growing steadily. 
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Previously,
createPrefetchResponseStreamintentionally never calledcontroller.close()on the wrapper stream, to prevent React Flight from erroring on unresolved references (dynamic holes). However, Chrome and Firefox keep unclosed ReadableStreams with pending reads as native GC roots, preventing the stream — and the entire FlightResponse captured in thereader.read().then(progress)closure chain — from being garbage-collected.Now that React Flight supports
unstable_allowPartialStreamas an option forcreateFromReadableStream(facebook/react#35731), we can close the stream normally. Flight will mark unresolved chunks as "halted" instead of erroring, which is the correct behavior for prefetch responses.Also removes the now-unnecessary
createUnclosingPrefetchStreamwrapper from the legacy prefetch path infetch-server-response.ts.closes #89485