Server Side Rendering (SSR) vs. Client Side Rendering (CSR) vs. Pre-Rendering using Static Site… (2024)

A comprehensive guide to the concepts of Traditional Server Side Rendering (SSR), Static Rendering, SSR at build time, Incremental Static Regeneration(ISR), SSR at request time, Pre-rendering with hydration on client side, Traditional Client Side Rendering (CSR) — and a review of Static Site Generators (SSG) like NextJS, VueSSR, NuxtJS, Gatsby and VuePress.

Server Side Rendering (SSR) vs. Client Side Rendering (CSR) vs. Pre-Rendering using Static Site… (2)

Server Side Rendering (SSR)

Server Side Rendering means generating the HTML for a webpage on the server side.

  • SSR-at request time: Server side rendering may happen at request-time, in which case the server dynamically generates the HTML for each URL request at run time.
    This is also called Dynamic Server Side Rendering.
  • SSR-at build time: Alternatively, the HTML for the web pages may be pre-generated on the server side at “build” time, and this pre-generated static HTML is returned to the browser, when the webpage is requested
    i.e. HTML is pre-generated, and is not generated on the fly at request-time.
    This is also called Pre-rendering.

Client Side Rendering (CSR)

Client Side Rendering means generating the HTML components on the browser side, by executing Javascript code within the browser that manipulates the HTML DOM to build the HTML nodes.

In Server Side Rendering (SSR) the HTML components of the webpage are generated on the server-side. When a browser requests a SSR web page, the browser receives a fully formed HTML web page with the HTML components already created, that looks something like this,

<!DOCTYPE html>
<html>
<head>
<title> Web Page Rendered on Server Side </title>
</head>
<body>
<h1> This is a Heading </h1>
<p> This is a paragraph </p>
<div>
<p> This is a form </p>
<form>
<label for="fname">First name:</label><br>
<input type="text" id="fname" name="fname"><br>
<label for="lname">Last name:</label><br>
<input type="text" id="lname" name="lname">
</form>
<div>

</body>
</html>

All the browser has to do is parse this HTML to generate the HTML DOM and display the web page.

Server Side Rendering can be done at build time, which pre-generates the HTML, or Server Side Rendering can be done at request time for each incoming request from the browser.

Dynamic Server Side Rendering(SSR) i.e. Server Side Rendering at request-time, requires a web-server running at run-time, to receive the navigation requests, fetch external data (on the server-side), dynamically generate the HTML, and then return the fully formed HTML to the browser.

Websites that are built using traditional server-side languages like PHP, ASP.NET (ASP), Java (JSP), Ruby, etc. are fully Server Side Rendered.

Note that browsers only understand HTML, CSS and Javascript, and the server-side languages (i.e. PHP, .NET, Ruby etc) basically programmatically generate HTML on the server-side and then send that HTML to the browser.

So whether you are using PHP, or Java, or Ruby, as your backend language, in SSR they all generate HTML that is returned to the browser. The server-side languages typically use some web framework and HTML templating during development to facilitate the generation of the HTML on the server-side.

Advantages of SSR

  • Better SEO and page ranking, since the HTML is fully formed on the server-side and web crawlers are more easily able to index the HTML pages.
  • Faster load time for the initial page render that a CSR App, since the HTML received from the server can be quickly parsed by the browser and displayed immediately, and does not require a separate JS bundle to be downloaded and executed to display the webpage.
  • Once the web page is visible in the browser it is fully interactive
    i.e. FCP = TTI
  • Since the HTML for the webpage is generated on the server-side, the webpage will display even if the browser Javascript is disabled.

Disadvantages of SSR

  • Poor responsiveness for low or no Internet connectivity, since every page navigation makes a round trip to the server to receive the HTML.
  • For Dynamic SSR, increased server load as the web traffic increases, since the server needs to dynamically generate HTML for every request.

In Client side rendering(CSR), the HTML components are generated on the client-side by executing Javascript code in the browser.

In this case when a browser requests a webpage, the initial server request returns a minimal HTML file that serves as the application container, and primarily contains the link to the React/Vue JavaScript bundle, that looks something like this,

<html> <head>
<title> CSR App </title>
</head>

<body>
<div id="app"> </div>
<script src="../src/index.js"> </script>

</body>

</html>

In this case there is no HTML for the browser to parse to generate the HTML DOM.

Instead the browser must fully download the JS bundle linked in the HTML, and then run the JS bundle in the browser (using the browser JS engine), which will then generate the web page HTML DOM on the client-side.

Additionally, clicking a navigation link within the app manipulates the HTML DOM client-side to create the DOM of the requested navigation, instead of requesting the HTML from the server (This is typically handled by a “router” module within the downloaded JS code eg. React-Router, Vue-Router).

The browser generates the HTML components on the client-side by executing the Javascript in the browser.

Instead of parsing HTML to create the DOM, client-side rendering uses JavaScript to create it.

Since for typical Client Side Rendered apps, the browser just receives a single HTML page that serves as the application container, they are also sometimes called Single Page Apps (SPAs),

Traditional React (i.e. Create-React-App), Vue apps are fully Client Side Rendered.

Advantages of CSR

  • Extremely fast and responsive after initial load, since after the initial load all the HTML for the website is generated on the client-side (by Javascript), without any round trips to the server to get the HTML. Also any real time data fetches can be handled client-side by client-side Javascript code making external API calls.

Disadvantages of CSR

  • Long initial load time, the browser must wait for the entire Javascript bundle to be downloaded and executed on the client-side, before the initial render. During this time the user is staring at a blank web page.
    Code-splitting, or lazy-loading strategies can be used to reduce the amount of assets that the browser needs to download for the initial page render, and this can greatly improve TTI (time-to-interactive) for apps with large bundles.
    — —
    https://ssr.vuejs.org/guide/routing.html#routing-with-vue-router
  • Negative impact on SEO and page ranking, since CSR web pages are mostly empty and only contain links to the JS code that generates the HTML, web crawlers may view them as empty pages.
    Google web crawlers can trigger a JS HTML rendering of the site, but if the JS bundle is large it may show a “loading” page and the web crawler may not correctly read the page thus be unable to index it.
  • User will see a blank page in case browser Javascript is disabled.
    If the user has disabled Javascript on their browser, the JS bundle will never be run on the client-side and so the HTML will never be generated, and the webpage will never be rendered. In this case the user will never see the website and just continue to see a blank page.

Single Page Applications (SPAs) that are written in front end frameworks like React, Vue etc., generate the HTML DOM when their Javascript code is executed by a Javascript engine (eg. Chrome V8, Nitro, SpiderMonkey etc).

Typically these apps are executed client-side by the browser Javascript engine, to generate the HTML DOM on the client-side.

However since NodeJS is also a JS engine (built on Chrome V8), it becomes possible to execute the React, Vue Javascript code on the server-side, in which case we can render the HTML components of the web page on the server-side.

In React, the ReactDOMServer object is similar to the ReactDOM object.
While the ReactDOM object is used to render HTML on the browser-side, the ReactDOMServer runs on the server-side and renders React components to static HTML on the server-side.

Apps written in frontend frameworks like React, Vue etc.where the majority of the codebase can be executed both within a browser (by browser JS) engine, and on the server-side (by Node JS), are called Universal Apps or Isomorphic Apps.

Hybrid Web Apps

Since it is possible to run React/Vue JS code both, on the browser-side and on the server-side, it is possible to build a website (or a webapp) where some webpages are pre-rendered on the server-side, and other webpages are rendered on the browser-side. Such apps are called Hybrid Web Apps.

Server Side Rendering generates static HTML at build time and static HTML is great for a fast initial render. Having a pre-rendered static HTML is also good for SEO since web crawlers can easily crawl and index the pre-rendered HTML. Also, if the HTML is pre-rendered the browser can display it even if the Javascript is disabled on the browser. However, on the downside since the pre-rendered HTML is static HTML, it is not reactive and also cannot fetch/update data in real time.

Client Side Rendering needs the full app JS bundle to be downloaded and initialized on the browser (client-side) before the webpage is viewable, and so the initial render may take some time. If the Javascript is disabled on the client-side then the HTML will never render, and the user will just see a blank screen. Also, client-side rendering is not SEO friendly since web crawlers typically just see an empty web page or a “loading page” while the JS is executing in the browser to generate the HTML. However, once the javascript code is downloaded on the client side, the client-side javascript code generates a way more responsive webpage (since no network roundtrip is required to generate HTML).

It be great if we could load a pre-rendered static HTML on initial render (so that the user can quickly view the website, and view the website even if the browser Javascript is disabled), and the client-side javascript code takes over once the app JS bundle is fully download and initialized in the browser (so that the remainder of the website interaction i.e. navigation to different webpages of the site or data fetching etc., happens via the client-side javascript).

This is exactly what Static Site Generators like Gatsby and NextJS do!!

When a browser requests a website developed using Gatsby or Next JS,

  1. The browser first gets the pre-rendered static HTML which it displays immediately. The pre-rendered static HTML is typically served from a CDN or Edge network making the “initial load” even faster.
    Also, since the web page is pre-rendered it improves SEO, since web crawlers can easily crawl and index the pre-rendered HTML.
  2. Meanwhile, the full client-side Javascript bundle is also sent to the browser, and this continues to download in the background on the browser-side (and does not block the initial render of the static HTML).
  3. Once the client-side Javascript code is fully downloaded and initialized, it is “rolled over” the webpage HTML and replaces the static HTML (in a process called hydration at client-side).
  4. Once hydration is complete, the website becomes a full client-side React app (or Vue App), and the client-side Javascript code takes over on the browser side i.e. after hydration website navigation or API calls to fetch data etc. are all handled by the Javascript code at the browser-side.

Hydration

When using Static Site generators, the HTML for the webpage is generated on the server-side(at build time). Static Site Generators send this static HTML and the app JS bundle to the browser when the browser accesses the website. The static HTML is displayed immediately within the browser, while the app JS bundle continues to download in the background. Now, after the app JS bundle is downloaded and initialized (on the browser-side), there is no need for the browser to re-generate the same HTML components on the browser-side.

This is because executing the JS code within the browser would generate exactly the same HTML components that were generated when that JS code was executed on the server-side.

React/Vue recognizes this, and instead of re-generating the HTML components on the client-side (for a web page whose HTML components were already generated on the server-side), React reuses the HTML components that were sent to it by the server, and attaches “interactivity” to it i.e. It attaches event handles etc. to it. This process is called “hydration”.

Hydration is a process where a frontend framework like React, VueJS re-uses the static HTML structure it receives from the server (that was created at server-side at build time), and instead of re-generating the HTML nodes on the browser, simply “breathes” event handlers and interactivity into it.

  • In React for example, an HTML can be generated on the server-side using ReactDOMServer.renderToString( <react-component>), which renders the HTML of the React component on the server-side and converts it to a static HTML string.
  • This static HTML is sent to the browser when that webpage is requested.
  • When the browser receives this static HTML, it calls ReactDOM.hydrate() function on the webpage instead of ReactDOM.render() . React.hydrate() is more light-weight than running React.render(), and ReactDOM.hydrate() assumes that that the HTML you received from the server-side is the same structure of the HTML that would have been created, had you run that React code on the browser-side by running ReactDOM.render(). So there is no need to run ReactDOM.render() on the browser-side, and instead run ReactDOM.hydrate() on the browser-side, which re-uses the HTML it received from the server, and attaches event handlers to it. i.e. “hydrates” it.

In summary,

  • ReactDOM.render() = generates HTML DOM on the client side
  • ReactDOM.hydrate() = takes the HTML it receives from server side and hydrates it.

The end result of ReactDOM.render() and ReactDOM.hydrate() is exactly the same, in that once these functions are run, the App in the browser is a fully client-side React App.

Think of ReactDOM.render() as assembling a computer hardware from scratch and installing an OS on it, and ReactDOM.hydrate() as having the computer hardware already assembled for you, and all you do is install the OS.
The end result of both cases is the same and indistinguishable.

Hydration makes transition of the client-side static HTML to a full client-side app, much faster and seamless, than re-generating the HTML nodes again by re-rendering HTML on the client-side.

Static Site Generators are frameworks that are built over the base frontend frameworks eg. React, Vue, and allow us to pre-render the HTML of the web apps by running then on the server-side at “build” time.

Static Site Generators (like NextJS, Gatsby, Nuxt, VuePress etc) run Single Page Applications (built in React, Vue etc.) on the server-side.

  • NextJS and Gatsby are built on the base React frontend framework.
  • NuxtJS and VuePress are built on the base Vue frontend framework.

Static Site Generators(SSGs) in effect execute the SPA Javascript code at build time and pre-generate the HTML on the server-side.

SSGs frameworks (like NextJS (SSR) and VueSSR) can also be configured to execute SPA Javascript code on the server side at request time, if needed.

The name Static Site Generators is somewhat of a misnomer. The “static” part refers to the fact that they generate “static HTML”. However these SSGs (i.e. NextJS, NuxtJS, Gatsby, VuePress) can all be used to write fully dynamic and interactive web apps.

We will examine NextJS and Gatsby which are two popular SSGs built on the React framework.

NextJS

Next.js is a React framework that supports static site generation. In NextJS each webpage is a React component, and individual webpages can generated using any of the following strategies,

  • Static Rendering: webpages are pre-rendered i.e a static HTML is generated at build(compile) time on the server-side.
    (using the getStaticProps() method, which executes on the server side)
    Note that in case the webpage accesses external data (via database or API), the data values are fetched at build time and baked into the static HTML i.e. in case you need to update the data values, you will need to re-generate (re-compile) the webpage.
  • Static Rendering with Incremental Static Regeneration(ISR): webpages are pre-rendered i.e. a static HTML is generated at build(compile) time on the server-side, and then a re-build of the static HTML for certain web pages are triggered if the webpage is accessed after the revalidation period.
    (This is done by adding a revalidate parameter within the getStaticProps() method, which executes on the server side).
    This approach is also called Incremental Static Regeneration (ISR) since only the webpages that have the revalidate prop are re-built, when triggered.
  • Static Rendering (with data fetched on server-side at request-time): webpage is pre-rendered at build time, but “data” portions of the webpage are left blank. i.e. a static HTML is pre-rendered at build time, but the data portions of the webpage are left blank.
    The data is then fetched dynamically on the server-side each time the webpage is requested by the browser, i.e. the data portions of the web page get populated on the server-side, and the pre-generated HTML populated with the data fetched at request-time, is returned to the browser. This approach is also sometimes called Dynamic Server Side Rendering.
    (This is implemented using getServerSideProps() method, which pre-renders a webpage whose data must be fetched at request time).
    Note that getServerSideProps only runs on server-side and never runs on the browser.

NOTE that this approach requires a web server to be running during request time that will receive the browser request and then call APIs on the server side to fetch data and populate the pre-rendered web page on the server-side, and then return this HTML.

If you want to use this strategy in VueJS, you can use VueSSR (https://ssr.vuejs.org/), or use the NuxtJS framework which is a higher-level solution built on the base Vue framework, and provides a smooth out-of -the-box experience by abstracting away a lot of the boilerplate, while also providing extra features like static site generation.

  • Static Rendering (with data fetched on client-side at request-time): webpage is pre-rendered, but data portions of the webpage are left blank, and populated by fetching data on the client side i.e The data is fetched dynamically at request-time, but by using client-side Javascript to invoke API calls.

Next.js lets us choose different pre-rendering strategies for the different pages of the same webapp, and thus allows us to create Hybrid Apps, where Static Generation may be used for most pages, and Dynamic Server-side Rendering may be used for other web pages.

Since NextJS generates Hydrid Apps, that may have some pages that need to access a web-server at run-time, Next JS typically has a web server running.

Next.js automatically determines if a page can be pre-rendered, by checking to see if the page contains getServerSideProps or getInitialProps.

If getServerSideProps or getInitialProps is present in a page, Next.js switches to Dynamic Server Side rendering for that page. Else, Next.js pre-renders the page to static HTML.

This feature allows Next.js to emit hybrid applications that contain both server-rendered and statically generated pages. i.e.

next build emits .html files for pages that can be pre-rendered and .js file for webpages with getServerSideProps.

For example, the result for the page pages/about.js would be: .next/server/pages/about.html
And if webpage contains getServerSideProps it would be: .next/server/pages/about.js

Gatsby JS

Gatsby is primarily a static side rendering framework and provides the following forms of rendering HTML.

  • Static Rendering: webpages are pre-rendered i.e a static HTML is generated at build(compile) time on the server-side, and any data required to populate the web page is fetched at build time.
  • Static Rendering (with data fetched on client-side at request-time): webpage is pre-rendered, but data portions of the webpage are left blank, and populated by fetching data on the client side i.e The data is fetched dynamically at request-time, but by using client-side Javascript to invoke API calls.

Note that unlike NextJS,
Gatsby does not provide options for Incremental Static Regeneration (ISR), or Static Rendering (with data fetched on server-side at request-time).

  • This means that Gatsby does not need a web-server running to handle run-time requests by the browser.
  • Also, since there is no web-server running and we do not have the option of ISR, any data updates in the app will require Gatsby to re-build the entire app to pre-render the new data in the static HTML.
    (Alternatively, one could Gatsby and fetch data client-side via API calls, but if your data updates frequently i.e. every few seconds, and a lot of your pages render via client-side API calls, then it kind of defeats the purpose of pre-rendering).

Note that hydration process occurs in both NextJS and Gatsby apps.

There seems to be a lot of confusion on the terms hydrate and rehydrate primarily due to the Google article “Rendering on the Web”.
https://developers.google.com/web/updates/2019/02/rendering-on-the-web

Hydrate and Rehydrate mean exactly the same thing, in that event handlers are attached to the pre-rendered static HTML that is received by the browser from the server. The only difference is what are the elements that are hydrated.

In case of NextJS when using Dynamic Server Rendering, all the static HTML that is rendered on the server side at run-time is (re-hydrated) on the client side. In case of Gatsby JS there is no Dynamic content rendered on the server side, so just the pre-rendered content is hydrated.

VuePress is the Gatsby equivalent but based on the VueJS framework.

As a general rule of thumb,

  • If most of the features of your webapp are behind a login screen, eg. a Dashboard app, you don’t really need SEO, and Create-React-App is a great option, to build a fully Client Side Rendered App, which will be extremely fast and responsive after initial load.
  • In case your site contains content that needs to be indexed by Google, and you need good SEO and page ranking, then use either NextJS or Gatsby.
  • If your website content needs to update every few seconds, eg. Newsfeed, Twitter like, Reddit etc. then use NextJS
  • If your website content is updated in-frequently, eg. Blog posts etc. then use GatsbyJS.
Server Side Rendering (SSR) vs. Client Side Rendering (CSR) vs. Pre-Rendering using Static Site… (3)

What is Rendering?

Before we conclude let us define what we mean by rendering, in the context of Server Side Rendering and Client Side Rendering.

Rendering (in the context of SSR and CSR), is the generation of the HTML components/tags.

  • In the case of CSR, the HTML is generated on the client side by executing Javascript code in the browser. The Javascript code is executed by the browser Javascript engine (eg. Chrome V8, Nitro, SpiderMonkey etc.)
  • In the case of SSR, the HTML is generated by executing code on the server-side. The server-side code to generate the HTML may be written in server-side languages (PHP, .NET etc) , or the server-side code could be a Single Page Application (written in React, Vue) that is executed server-side by Node JS.

CSR or SSR “rendering” should not be confused with “web page rendering” that is performed by a browser engine (like Webkit, Blink, Gecko, etc), when it receives an HTML file, and builds the “Render Tree” from the DOM and CSS OM, and then “paints” the web page.

Ref:
https://www.seobility.net/en/wiki/Rendering

https://developers.google.com/web/fundamentals/performance/critical-rendering-path/constructing-the-object-model

That is a completely different definition of “rendering” and not what we are talking about in the context of SSR and CSR.

Server Side Rendering (SSR) vs. Client Side Rendering (CSR) vs. Pre-Rendering using Static Site… (4)

Found this post helpful? Hit the 👏 👏 👏 button a few times to show how much you liked it! 🙂

Follow me on Medium for the latest updates and posts!

Server Side Rendering (SSR) vs. Client Side Rendering (CSR) vs. Pre-Rendering using Static Site… (2024)
Top Articles
Latest Posts
Article information

Author: Fredrick Kertzmann

Last Updated:

Views: 6105

Rating: 4.6 / 5 (66 voted)

Reviews: 81% of readers found this page helpful

Author information

Name: Fredrick Kertzmann

Birthday: 2000-04-29

Address: Apt. 203 613 Huels Gateway, Ralphtown, LA 40204

Phone: +2135150832870

Job: Regional Design Producer

Hobby: Nordic skating, Lacemaking, Mountain biking, Rowing, Gardening, Water sports, role-playing games

Introduction: My name is Fredrick Kertzmann, I am a gleaming, encouraging, inexpensive, thankful, tender, quaint, precious person who loves writing and wants to share my knowledge and understanding with you.