This repo demonstrates the difference in server-side rendering performance between React Server Components (RSC) and standard streaming SSR.
To reproduce the benchmark, clone the repo and run:
nvm usenpm cinpm run buildnpm start
In a separate terminal, start the benchmark:
npm test
The tests hit a Node.js server that renders a list of 10,000 items.
The benchmark uses autocannon with 50 concurrent connections and reports latency and requests per second (RPS).
The project uses Parcel for bundling, but results should be similar with other RSC bundlers or frameworks.
Route: /ssr/regular
Serves standard streaming SSR using renderToPipeableStream.
npx autocannon -c 50 -d 10 --renderStatusCodes --excludeErrorStats http://localhost:3000/ssr/regular
Running 10s test @ http://localhost:3000/ssr/regular
50 connections
┌─────────┬───────┬────────┬────────┬────────┬───────────┬───────────┬─────────┐
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
├─────────┼───────┼────────┼────────┼────────┼───────────┼───────────┼─────────┤
│ Latency │ 65 ms │ 145 ms │ 245 ms │ 298 ms │ 150.31 ms │ 170.27 ms │ 3378 ms │
└─────────┴───────┴────────┴────────┴────────┴───────────┴───────────┴─────────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬────────┬─────────┐
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
│ Req/Sec │ 308 │ 308 │ 331 │ 336 │ 329.1 │ 7.69 │ 308 │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
│ Bytes/Sec │ 39.9 MB │ 39.9 MB │ 42.9 MB │ 43.5 MB │ 42.6 MB │ 999 kB │ 39.9 MB │
└───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴────────┴─────────┘
┌──────┬───────┐
│ Code │ Count │
├──────┼───────┤
│ 200 │ 3291 │
└──────┴───────┘
Req/Bytes counts sampled once per second.
# of samples: 10
3k requests in 10.02s, 426 MB read
Route: /ssr/rsc
Renders a Server Component to HTML.
This type of rendering is not provided by React out of the box and it’s implemented in the frameworks:
- Render the Flight stream
- Render the Fizz stream from the Flight stream data
- Inject the Flight data into the HTML for client hydration
npx autocannon -c 50 -d 10 --renderStatusCodes --excludeErrorStats http://localhost:3000/ssr/rsc
Running 10s test @ http://localhost:3000/ssr/rsc
50 connections
┌─────────┬────────┬────────┬─────────┬─────────┬───────────┬────────────┬─────────┐
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
├─────────┼────────┼────────┼─────────┼─────────┼───────────┼────────────┼─────────┤
│ Latency │ 133 ms │ 571 ms │ 4814 ms │ 7858 ms │ 760.73 ms │ 1133.58 ms │ 9261 ms │
└─────────┴────────┴────────┴─────────┴─────────┴───────────┴────────────┴─────────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Req/Sec │ 19 │ 19 │ 26 │ 42 │ 29.2 │ 6.99 │ 19 │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Bytes/Sec │ 10.8 MB │ 10.8 MB │ 14.8 MB │ 23.8 MB │ 16.6 MB │ 3.96 MB │ 10.8 MB │
└───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
┌──────┬───────┐
│ Code │ Count │
├──────┼───────┤
│ 200 │ 292 │
└──────┴───────┘
Req/Bytes counts sampled once per second.
# of samples: 10
368 requests in 10.02s, 166 MB read
26 errors (26 timeouts)
Route: /only/flight
Renders the Server Component as Flight (JSON) only.
npx autocannon -c 50 -d 10 --renderStatusCodes --excludeErrorStats http://localhost:3000/only/flight
Running 10s test @ http://localhost:3000/only/flight
50 connections
┌─────────┬───────┬────────┬─────────┬─────────┬───────────┬───────────┬─────────┐
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
├─────────┼───────┼────────┼─────────┼─────────┼───────────┼───────────┼─────────┤
│ Latency │ 58 ms │ 302 ms │ 1778 ms │ 5944 ms │ 419.79 ms │ 888.33 ms │ 9855 ms │
└─────────┴───────┴────────┴─────────┴─────────┴───────────┴───────────┴─────────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬────────┬─────────┐
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
│ Req/Sec │ 102 │ 102 │ 104 │ 108 │ 104.7 │ 2.01 │ 102 │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
│ Bytes/Sec │ 36.5 MB │ 36.5 MB │ 37.3 MB │ 38.7 MB │ 37.5 MB │ 709 kB │ 36.5 MB │
└───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴────────┴─────────┘
┌──────┬───────┐
│ Code │ Count │
├──────┼───────┤
│ 200 │ 1047 │
└──────┴───────┘
Req/Bytes counts sampled once per second.
# of samples: 10
1k requests in 10.02s, 375 MB read
5 errors (5 timeouts)
Route: /only/fizz
Renders the Server Component via Fizz using cached Flight data, skipping the initial Flight request.
npx autocannon -c 50 -d 10 --renderStatusCodes --excludeErrorStats http://localhost:3000/only/fizz
Running 10s test @ http://localhost:3000/only/fizz
50 connections
┌─────────┬───────┬────────┬────────┬─────────┬───────────┬───────────┬─────────┐
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
├─────────┼───────┼────────┼────────┼─────────┼───────────┼───────────┼─────────┤
│ Latency │ 41 ms │ 143 ms │ 287 ms │ 2559 ms │ 180.17 ms │ 421.98 ms │ 5525 ms │
└─────────┴───────┴────────┴────────┴─────────┴───────────┴───────────┴─────────┘
┌───────────┬─────┬──────┬─────────┬─────────┬─────────┬─────────┬─────────┐
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
├───────────┼─────┼──────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Req/Sec │ 0 │ 0 │ 331 │ 341 │ 274.9 │ 120.24 │ 74 │
├───────────┼─────┼──────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Bytes/Sec │ 0 B │ 0 B │ 42.9 MB │ 44.2 MB │ 35.6 MB │ 15.6 MB │ 9.58 MB │
└───────────┴─────┴──────┴─────────┴─────────┴─────────┴─────────┴─────────┘
┌──────┬───────┐
│ Code │ Count │
├──────┼───────┤
│ 200 │ 2749 │
└──────┴───────┘
Req/Bytes counts sampled once per second.
# of samples: 10
3k requests in 10.02s, 356 MB read