Add Flight SSR benchmark fixture#36180
Open
unstubbable wants to merge 40 commits intofacebook:mainfrom
Open
Conversation
|
Comparing: 80b1cab...cd406da Critical size changesIncludes critical production bundles, as well as any change greater than 2%:
Significant size changesIncludes any change greater than 0.2%: (No significant changes) |
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
This PR adds a benchmark fixture for measuring the performance overhead of the React Server Components (RSC) Flight rendering compared to plain Fizz server-side rendering.
Motivation
Performance discussions around RSC (e.g. #36143, #35125) have highlighted the need for reproducible benchmarks that accurately measure the cost that Flight adds on top of Fizz. This fixture provides multiple benchmark modes that can be used to track performance improvements across commits, compare Node vs Edge (web streams) overhead, and identify bottlenecks in Flight serialization and deserialization.
What it measures
The benchmark renders a dashboard app with ~25 components (16 client components), 200 product rows with nested data (~325KB Flight payload), and ~250 Suspense boundaries in the async variant. It compares 8 render variants: Fizz-only and Flight+Fizz, across Node and Edge stream APIs, with both synchronous and asynchronous apps.
Benchmark modes
yarn benchruns a sequential in-process benchmark with realistic Flight script injection (tee +TransformStream/Transformbuffered injection), matching what real frameworks do when inlining the RSC payload into the HTML response for hydration.yarn bench:bareruns the same benchmark without script injection, isolating the React-internal rendering cost. This is best for tracking changes to Flight serialization or Fizz rendering.yarn bench:serverstarts an HTTP server and usesautocannonto measure real req/s atc=1andc=10. Thec=1results provide a clean signal for tracking React-internal changes, whilec=10reflects throughput under concurrent load.yarn bench:concurrentruns an in-process concurrent benchmark with 50 in-flight renders viaPromise.all, measuring throughput without HTTP overhead.yarn bench:profilecollects CPU profiles via the V8 inspector and reports the top functions by self-time along with GC pause data.yarn startstarts the HTTP server for manual browser testing. Appending.rscto any Flight URL serves the raw Flight payload.Key findings during development
On Node 22, the Flight+Fizz overhead compared to Fizz-only rendering is roughly:
bench:bare): ~2.2x for sync, ~1.3x for asyncbench:server, c=1): ~2.9x for sync, ~1.8x for asyncTransformStreambuffering)The async variant better represents real-world applications where server components fetch data asynchronously. Its lower overhead reflects the fact that Flight serialization and Fizz rendering can overlap with I/O wait times, making the added Flight cost a smaller fraction of total request time.
The benchmark also revealed that the Edge vs Node gap is negligible for Fizz-only rendering (~1-2%) but grows to ~15% for Flight+Fizz sync even without script injection. With script injection (tee +
TransformStreambuffering), the gap roughly doubles to ~30% for sync. The async variants show smaller gaps (~5% without, ~10% with injection).