The Benefits of Server Side Rendering Over Client Side Rendering
Most of our pages on walmart.com are using server side rendering (henceforth SSR) with only a few unique exceptions.
We are using server side rendering for two reasons:
- Performance benefit for our customers
- Consistent SEO performance
Due to the benefits of SSR, when we transformed our stack to React and Nodejs, we put a lot of time and effort in optimizing SSR performance. One of our key metrics for measuring performance is “above the fold” render. Our Electrode framework that we open sourced has multiple modules to improve the performance of SSR and I blogged previously about the benefit of those modules.
When we announced Electrode and its focus on SSR, I received tons of questions and comments asking about the benefit of SSR. This blog post focuses on the performance benefit of using SSR — Andrew Farmer and Patrick Hund did a great job covering the SEO benefits.
The Theoretical Performance Benefit
Here is a very simple timeline diagram(super simple)to showcase the difference between SSR and CSR.
The main difference is that for SSR your server’s response to the browser is the HTML of your page that is ready to be rendered, while for CSR the browser gets a pretty empty document with links to your javascript. That means your browser will start rendering the HTML from your server without having to wait for all the JavaScript to be downloaded and executed. In both cases, React will need to be downloaded and go through the same process of building a virtual dom and attaching events to make the page interactive — but for SSR, the user can start viewing the page while all of that is happening. For the CSR world, you need to wait for all of the above to happen and then have the virtual dom moved to the browser dom for the page to be viewable.
Another Bonus: The blank page flicker that happens with CSR also doesn’t really happen with SSR — though most people avoid it by having a loading image sent down in the server response which is removed when everything is done loading.
Now, there are a few caveats:
- While the page is rendered earlier and the customer can see the page sooner, they can’t really interact with it until react is done executing. If the customer is really fast and clicks a button, the action won’t be executed until React is done executing;
- SSR TTFB(Time To First Byte)is slower than CSR, because your server will have to spend the time to create the HTML for your page instead of just sending out a relatively empty response;
- SSR throughput of your server is significantly less than CSR throughput. For react in particular, the throughput impact is extremely large.
ReactDOMServer.renderToString
is a synchronous CPU bound call, which holds the event loop, which means the server will not be able to process any other request tillReactDOMServer.renderToString
completes. Let’s say that it takes you 500ms to SSR your page, that means you can at most do at most 2 requests per second. *BIG CONSIDERATION*
Real Use Case
Below are production applications of walmart.com rendered with SSR vs CSR.
We compared three of our applications(home, category, and search) in SSR vs CSR. These are the chrome network screen grabs of the pages being rendered. You’ll notice that SSR renders faster, and that using CSR has the blank white page while loading. Most applications that use CSR will obviously replace the blank white page with a loading icon, but since we use SSR for our normal operations, when forced into CSR mode, the pages are blank. Please note these are one off captures, with our machines, at a certain time of day with the current prod build, so individual performance can vary-but this should be the general trend that you see for apps.
Here is the first server response for home, category and search pages. I would ignore the green bar, because that is more relative compared to the rest of the network graph. The two things I want to call attention to is the document size and the TTFB. Since the server is responding with HTML for the page, you’ll notice the document size for SSR is always bigger. Another point that was talked about earlier, the CSR response is faster(except for home page for some reason in this test).
I can’t stress enough though that these captures are variable based on application, latency, server, location, and a bunch of other variables, so they shouldn’t be taken as scientific fact, but more of a general trend.
Electrode
When we did A/B tests on SSR vs CSR, the trend above is what we would see, and our numbers showed better engagement from the customer with rendering early.
For these reasons, our open source application platform, Electrode is heavily focused on SSR. It’s turned on by default, and we have a few modules built around optimizing SSR. In another post, I showcased that with two of the modules, you can improve RenderToString() time by 70%.
Big thank you to Mayakumar and Caoyang for helping me review and polish this blog post.