Don't develop your web apps with full SSR but use hybrid SSR/CSR approach!
Tags: nextjs, nuxt, webdev
Published: 2022-04-16 12:14:18

Nowadays, many frontend web apps are using Nodejs based frameworks such as [Nextjs](https://nextjs.org/) or [Nuxtjs](https://nuxtjs.org/). But some of their large-scale web apps are suffering performance issues. Here, I am going to explain one of the system design topics frontend engineers would face.

**Lesson: Don't develop your web apps with full SSR but use hybrid SSR/CSR approach**

First of all, You can learn the concepts of SSR, CSR, SSG, and ISR in the following article.

[Visual Explanation and Comparison of CSR, SSR, SSG and ISR](https://dev.to/pahanperera/visual-explanation-and-comparison-of-csr-ssr-ssg-and-isr-34ea)

Furthermore, full Server-side rendering (Full SSR) is to generate web content on the server at every request time. On the other hand, most frameworks also support a hybrid SSR/CSR approach, which produces web contents on the server at the first request time but generates other pages on user browsers via internal page navigations.

Some people would consider that the full SSR is better than hybrid SSR/CSR for security, performance, and SEO reasons as long as they can bear the increasing server cost. But this is almost surely false because Nodejs, the base of Nextjs and Nuxtjs runtime, is a single-threaded application.  

It would be best to read this official article to learn how Nodejs takes advantage of single-threading.

[Don't Block the Event Loop (or the Worker Pool)](https://nodejs.org/en/docs/guides/dont-block-the-event-loop/)

In short, a single-threaded application is precisely like an excellent director. A Nodejs director can receive tons of tasks from clients (browsers) one after another, give instructions to his backend workers, and receive the task outcomes. Unfortunately, he is not a good worker, and it isn't nice to assume he can do both direction tasks and backend work. Thus, any computation-intensive jobs such as full SSR or large JSON parsing would lead to the tremendous latency of the entire application response.

You can also read a well-written story from Maaspteh about his struggle with making his full-SSR web app performant. 

[NodeJS and React SSR, the need for foul play](https://blog.ah.technology/nodejs-and-react-ssr-the-need-for-foul-play-30c0f795e72a)

It is safe to assume that hybrid SSR/CSR applications with moderately optimized code can produce 100 to 200 requests per second at the stress testing, but the full SSR site can bring out only 16 to 50 requests per second. Alas!

Instead, you should fully take advantage of the nature of single-threaded applications in the following way.

1. Use SSG/ISG rendering for mostly static but potentially frequently updated pages. Nextjs strongly supports [this idea](https://nextjs.org/docs/basic-features/pages).
2. Make use of lazy loading and conditional rendering for above-the-fold contents. Especially, be aware of components with a large DOM size like accordion menus and dynamic recommendation contents. 

As a final note, you could try using full SSR for specific pages whose visuals change almost entirely from the previous page, as the browser would be too slow to parse, render, and re-style the new DOM trees. In such a case, a developer just need to change internal links such as [next/links](https://nextjs.org/docs/api-reference/next/link) to the standard <a> tag.

Happy Coding!