Choosing between client-side rendering, server-side rendering and static site generation for React apps

Subscribe to my newsletter and never miss my upcoming articles

In the beginning of every new React project, one question inevitably floats to the surface - should we use client-side rendering (CSR), server-side rendering (SSR) or generate a static site (SSG). It is a strategic decision which depends on several key factors.

But first, a quick review!

Note: Feel free to skip the review if you are already familiar with the basics of the three approaches. 🚀

Client-side rendering

In essence, CSR simply means that we are using Javascript to render the contents of our app in the browser. Imagine a standard single page React application built with create-react-app or a similar tool. When we execute the build script, what we can expect to find in our build folder (among other things) is a relative bare-bone index.html file together with our Javascript bundle (likely split in chunks).

Whenever someone visits our app in their browser, they would be able to only see the contents of the (almost empty) index.html file until the necessary Javascript is downloaded and executed. Afterwards, users will be able to both view and interact with the contents of our app.

At this point, additional data may be fetched from a server and displayed by the app, if needed.

Static site generation

By contrast, when we are creating a static site, we need all the contents and data of our app to be available upfront. The reason is that using SSG means we generate full-fledged HTML files already during the build step.

What we gain with this approach is that the user doesn't have to wait for any Javascript to download and execute before being able to see the initial content on the page. On the flip side, needing all the data upfront also means that whenever a change is needed, we have to recreate and redeploy the entire build. This can quickly become cumbersome if frequent updates are needed.

Still, static sites can be an excellent tool. And frameworks like Gatsby and NextJS make it increasingly easy to create them in React.

Server-side rendering

Finally, server-side rendering means that we are using a server to render the contents of our HTML files and serve them to the client when requested. As with SSG, the user does not have to wait for the Javascript to be downloaded and executed before being able to view the page initially.

An important difference is that instead of having already generated static files, we are able to dynamically determine the content what is being served to the client. No rebuilds necessary. The trade-off is that what we gain in flexibility comes at the cost of an additional server and very possibly some added complexity compared to the other options.

Luckily, tools like NextJS do a good job of streamlining the development of React apps with SSR.

Decision time

Now that we have a basic understanding of what our options are, let's take a closer look at how we can choose between them.

🔍 Search engine optimization

The importance of SEO is a key consideration. As already mentioned, with CSR the initial HTML file is very minimal and Javascript is needed to render the app. This also means that the initial load time before meaningful content appears would be longer with CSR than with the alternatives. This is bad for SEO.

By contrast, with both SSR and SSG, the initial HTML files already contain meaningful content. This makes them easily crawlable and indexable by search engines. In addition, creating page-specific link previews when sharing links on social platforms, for example, is trivial with SSR and SSG while downright impossible with CSR (unless we use a service like prerender.io to generate them).

Is SEO always a must? Not every app needs to be search engine optimized. SEO might not be relevant if the entire app is behind a login, for example. In this case, the contents are only accessible to logged in users anyway so the lack of SEO is not a huge concern.

🌀 Dynamic content

The second important factor to consider is how dynamic is the content of the website we are building. One of the main drawbacks of the SSG approach is that in order to update the content of the app, we need to rebuild it. This might be perfectly fine if the app consists of mostly static content and is not frequently updated. A good use case for SSG would be a personal blog or a marketing website, for example.

However, in many cases, our applications need to be a lot more dynamic than that. Consider a dashboard app which needs to display up to date, personalised data for each user. It would be impractical to try to generate this statically. In this case opting for CSR is a much better choice. With it, we are able to fetch the necessary data for the specific user on the client, display it and seamlessly keep it up to date.

Here is another scenario. What if we are building a news site, where the content is both public and constantly updated. What if, in addition, there is some user generated content involved like comments under the articles, for example? Once again, SSG would not be ideal in this context. It would be much preferable to take advantage of SSR instead, with its ability to serve dynamic, non-stale, search engine optimized HTML files and easily reflect updates upon each request.

⌛ Initial load time

Initial load time can be an important UX consideration, especially if our users are in a place with slow internet connection or we expect the app to be used on (relatively) old devices. With both SSG and SSR we are able to show initial meaningful HTML on the screen. Even though users cannot immediately interact with it (we need Javascript for that), the perception is that the app loads quickly. It is worth noting that, with the use of a CDN, statically generated sites would probably perform better than SSR since the content is already generated and cached. However, we also run the risk of it being stale at request time.

On the other hand, using CSR means that all the users see is the empty HTML file (or, at best, a loading screen) until the necessary Javascript is downloaded, executed and able to render the content of the app. This might give users the initial impression that the app is too slow.

🌐 Infrastructure

Finally, it is important to think about the ways in which we build and deploy our React apps and the added complexity or cost this might entail. Probably the simplest approach to deployment is if our app build consists of static files. This means we could directly deploy it on a CDN service and our website would be live. With both CSR and SSG this is exactly the case.

With SSR the infrastructure setup is more complex. Using this paradigm means we need a server to pre-render the page into HTML on every request. And even though services like Vercel make the deployment of NextJS apps almost seamless, it is important to keep in mind that as the number of users for our app increases, the infrastructure cost might increase with it.

Conclusion

Here is a quick summary for what we have discussed so far.

CSRSSGSSR
SEO❌✅✅
Dynamic content✅❌✅
Initial load time❌✅✅
Static build✅✅❌

So which approach should we choose? As usual, there is no one size fits all solution. The choice should always be determined by our particular use case.

There is also the possibility to mix and match these approaches for different parts of our app. If you want to give combining them a shot, NextJS is especially flexible in this respect.

Happy coding! ✨

Bhargav Ponnapalli's photo

This was super helpful!

Iva's photo

Thanks, I am so glad you liked it!

Aniruddh Mukherjee's photo

I love the clarity in your writing!

Iva's photo

Thanks so much! 😊

shadowtime2000's photo

The thing with NextJS though is that it has support for hybrid rendering so in an app you can have the blog which is static and then you can SSR the actual app which has a ton of dynamic content.

Iva's photo

Completely agree! As mentioned above, NextJS is great for combining SSR and static generation if needed. 😉