react: Server-side rendering performance degradation with renderToPipeableStream
Hello!
When switching from renderToString to renderToPipeableStream, I run load tests on the application, and found a decrease in server throughput, from 50 to 15 RPS, and an increase in response timings.
When profiling the CPU, I see a large overhead on the internal work of the stream, specifically the methods Writable.write and Writable.uncork.
All these method calls together take more than twice as much CPU time (about 50-60ms) as rendering my test page (about 15-20ms)
Also, I don’t want to give the HTML to the client in the stream, this approach has some disadvantages. So I have to buffer the data, and it slows down the application a bit more.
CPU profiler in production mode:
CPU profiler in development mode:
My custom Writable stream with buffering:
class HtmlWritable extends Writable {
chunks = [];
html = '';
getHtml() {
return this.html;
}
_write(chunk, encoding, callback) {
this.chunks.push(chunk);
callback();
}
_final(callback) {
this.html = Buffer.concat(this.chunks).toString();
callback();
}
}
And rendering flow:
import { renderToPipeableStream } from 'react-dom/server';
new Promise((resolve, reject) => {
const htmlWritable = new HtmlWritable();
const { pipe, abort } = renderToPipeableStream(renderResult, {
onAllReady() {
pipe(htmlWritable);
},
onError(error) {
reject(error);
},
});
htmlWritable.on('finish', () => {
resolve(htmlWritable.getHtml());
});
});
About this issue
- Original URL
- State: open
- Created 2 years ago
- Reactions: 5
- Comments: 22 (1 by maintainers)


The initial fix is in 18.1.0.
I’m going to continue working on this and will likely have future PRs but can’t say exactly when. If you look for titles with
[Fizz]in the title that’s likely where they will be. If I remember I’ll ping you here or tag you in the future workOngoing work in https://github.com/facebook/react/pull/24291.
Thanks! Create few examples from this - https://github.com/SuperOleg39/react-ssr-perf-test
At first, I made comparsion between
renderToStringwith 17 and 18 versions (call itreact@18 legacy). React 17 - 50 RPS React 18 - 70 RPS, and I only changed a react and react-dom versions.Then I tested
renderToPipeableStream(call itreact@18 stream) I got timings around 1.5s for responses, problem was inapp.use(compress());middleware:After removal this middleware, I got around 2 RPS, 300+ ms CPU work for request. Still a big overhead for stream internals:
At last, tried buffering (call it
react@18 buffering), and got around 15 RPS. CPU profile: