Server-Side Rendering (SSR) and Client-Server Rendering (CSR) are very popular rendering techniques in web development. You hear them more often when discussing libraries and frameworks like React.js, Vue.js, Next.js, etc.
In this article, learn what SSR and CSR mean. Also, you will discover some examples using Javascript, React.js, and Next.js and explanation of the pros and cons of using these concepts.
First, what is Rendering? It is the conversion of a code into the web page users see on their browsers. The two prominent rendering techniques that dominate web development are SSR and CSR. Each of these offers unique advantages and caters to specific web development needs. In CSR, most of the rendering happens on the client, i.e., on a browser with Javascript. In SSR, the rendering happens on a server. An example is using any backend technology like Node.js, PHP, etc.
This article aims to teach and let you know about the ins and outs of SSR and CSR by marking the key differences, usefulness, and drawbacks known to them and to select the one that will be optimal for their specific web development projects.
Let us dive deep into how server-side and client-side rendering works. Let's begin with SSR.
Rendering determines how the HTML, CSS, and JavaScript of a web page are processed to produce a viewable page. The two main rendering approaches are server-side rendering (SSR) and client-side rendering (CSR). With SSR, the server generates the full HTML content for each page and sends it to the browser, so users see content quickly. CSR involves the browser receiving a minimal HTML file and using JavaScript to render content dynamically.
Selecting the suitable rendering method affects your application's performance, search engine optimization (SEO), and user experience. SSR can provide faster initial page loads and better SEO since content is immediately available for search engines to crawl. CSR offers greater interactivity and smoother transitions within the application after the initial load.
Understanding the trade-offs between SSR and CSR helps you align the rendering strategy with your project's specific needs. Factors such as content type, performance requirements, SEO considerations, use of a headless CMS, and target audience should influence your decision.
An HTTP request is made to the server, which processes the requests and generates the content(which can be HTML, JSON, or other formats). The content generated, along with the necessary Javascript, is then sent back to the client's browser.
In Server-Side Rendering (SSR), the initial response may be a pre-rendered HTML page that gets enhanced by JavaScript on the client side.
One major benefit of server-side rendering is the page loading speed. This is a very important criterion for user experience.
Considering this, we can see that in SSR, the heavy lifting is taken care of on the server. This then reduces the workload on the browser(client) as there is little to no work left for the browser. It is ready to use on the fly.
The benefits of SSR are below:
The drawbacks of SSR are:
Create a new folder of your choice and give it any name. Inside it, create a file called server.js
and add the following code:
1const http = require("http");
2
3function renderHomePage(data) {
4 return `
5 <!DOCTYPE html>
6 <html lang="en">
7 <head>
8 <meta charset="UTF-8">
9 <title>SSR Example</title>
10 </head>
11 <body>
12 <h1>Welcome!</h1>
13 <p>This content is pre-rendered on the server.</p>
14 <p>Data from server: ${JSON.stringify(data)}</p>
15 </body>
16 </html>
17 `;
18}
19
20const server = http.createServer((req, res) => {
21 const data = { message: "Hello from the server!" };
22 const htmlContent = renderHomePage(data);
23 res.writeHead(200, { "Content-Type": "text/html" });
24 res.write(htmlContent);
25 res.end();
26});
27
28server.listen(3000, () => console.log("Server listening on port 3000"));
The code for this example can be found on GitHub here. The Node.js server code above demonstrates the following:
The above code snippet is an example of SSR. In this example, everything that the client's web browser will display has been pre-rendered on the server.
Now spin up the server by running the command below:
#This starts or runs the node server above
node server
Open your browser and enter the application URL: http://localhost:3000. Here is the output of the above code sample when we run the command above.
A good way to check that the content on the web page was server-side rendered is to check the "View page source". Do this by right-clicking on the page and then clicking the "View Page Source" option. Here is what it looks like when we check for the example code above.
The image above clearly shows that the content on the client was rendered on the server side.
Another way to determine whether the content of your page is SSR or CSR is by inspecting the "Network" tab of your browser's developer tools. By navigating to the "Network" tab and refreshing the page, you can observe the requests and responses between your browser and the server. Then, you can examine the server's response by selecting the "Preview" or "Response" tab for a specific request.
Here's what it looks like when we check the preview tab for the above example:
NOTE: The "Preview" tab shows data that is served on the server localhost, so from the above image, all of the content is being rendered on the server.
Next.js Components rendered on the server side are called server components. The first time Next.js renders a component, it pre-renders it from the server. Moreover, all components from Next.js 13 and above are server-side rendered by default.
1const Products = () => {
2 const frontend = ["React", "Vue", "Angular", "Next JS"];
3 return (
4 <div>
5 <h1>React App</h1>
6 <h2>Products Page</h2>
7 <p>{frontend.join(", ")}</p>
8 </div>
9 );
10};
11
12export default Products;
The code for this example can be found on GitHub here.
The code above is very similar to React.js, but in this case, it is rendered by default on the server side. Here's what the page looks like on the browser:
We can confirm this by checking the "Response" tab in our "Network" tab in Chrome developer tools.
We can see that everything on the page is server-side rendered.
An HTTP request is made to the server. The server receives the request and responds by sending the client a bunch of JavaScript-bundled files. The client then proceeds to process the JavaScript. The processed JavaScript modifies the DOM and renders the final HTML for the client's users.
In simple terms, CSR is when your website or web application renders HTML in the browser by processing JavaScript.
However, there's a common misconception about client-side rendering. While it's true that the client plays a significant role in rendering, it doesn't handle the entire rendering process. Instead, in client-side rendering, the client handles the bulk of the rendering work, leaving minimal or no rendering tasks for the server.
The Benefits of CSR include:
The Drawbacks of CSR include:
Create a new folder with the name client-side-rendering
. Inside it, create a file index.html
and add the following code:
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <meta charset="UTF-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 <title>CSR</title>
7 </head>
8 <body>
9 <h1>Javascript Application</h1>
10 <h4>Built with Client-Side Rendering (CSR)</h4>
11 <script src="./script.js"></script>
12 </body>
13</html>
The code for the example above can be found on GitHub here.
Next, create another new file script.js
and add the following code:
1// script.js
2const body = document.querySelector("body");
3
4const data = ["React", "Vue", "NextJS"];
5
6body.innerHTML += `<p>${data.join(", ")}</p>`;
The code for the example above can be found on GitHub here.
The above example is a case of CSR. The <h1>
Javascript Application </h1>
and <h4>
built with Client-Side Rendering (CSR) </h4>
come from the server; the script.js
file is downloaded from the server, but then the client will then have to execute the code in the script.js
file which renders the data array content React, Vue and NextJS on the page.
Here is a picture of the outcome of the above code sample:
Let us proceed to check if it is CSR rendered by checking the “View page source” of the page.
Here's a pictorial example of how the page source looks like:
We can see that the content of the title
, h1
, and h4
elements comes from the server. The data array content is then loaded and executed from the script.js
file and displayed on the page. The data array content is then loaded and executed from the script.js
file and displayed on the page.
1const App = () => {
2 const frontend = ["React", "Vue", "Angular", "Next JS"];
3 return (
4 <div>
5 <h1>React App</h1>
6 <h2>Products Page</h2>
7 <p>{frontend.join(", ")}</p>
8 </div>
9 );
10};
11
12export default App;
The code for this example can be found on GitHub here.
The App
component in this example is rendered on the client side to form the HTML in the picture below:
NOTE The whole content of the App component is rendered on the client side. We can confirm this by using any of the methods mentioned above to check whether your code is Client-Side or Server-side rendered.
In the screenshot above, the server only renders the <title>
tag as indicated. Other content, such as the page's body, is loaded from a script file, represented by the image referenced on line 21
in the Response tab.
Next.js components that are rendered on the client side are called Client components. Client Components enable you to add client-side interactivity. They are pre-rendered on the server and hydrated on the client.
Hydration in Next.js client components ensures that the server-rendered HTML is seamlessly converted into interactive React components on the client side, enabling dynamic user experiences.
Let's look at this component below:
1"use client";
2import { useState } from "react";
3
4const Counter = () => {
5 const [count, setCount] = useState(0);
6
7 const handleButtonClick = () => {
8 setCount(count + 1);
9 };
10 return (
11 <div>
12 <p>You clicked {count} times</p>
13 <button onClick={handleButtonClick}>Click Me</button>
14 </div>
15 );
16};
17export default Counter;
The code for this example can be found on GitHub here.
The Counter
Component can initially be mistaken for a Server Component. But since it has buttons, listens for clicks (the onClick event listener), and uses hooks like useState()
, it must become a client Component to work well on the user's browser.
We make it a Client Component by adding the "use client"
directive at the top of the file, as seen in the Counter
Component above. Next.js will throw an error if you do not use the "use client"
directive.
Here are some key features to know before choosing between SSR or CSR.
Feature | SSR (Server-Side Rendering) | CSR (Client-Side Rendering) |
---|---|---|
SEO | Generally better. Search engines can easily get pre-rendered HTML content on the server, leading to better organic ranking. | Potentially requires additional SEO work. Search engines might have difficulty indexing dynamically generated content by Javascript. This requires additional SEO methods and strategies. |
Initial Load Time | Users see the content almost instantly as the server delivers a fully rendered HTML page. This is beneficial for content-heavy sites and users with slower internet connections. | The initial page load might be slower as the browser needs to download and execute JavaScript before displaying content. Development Complexity |
Development Complexity | Requires server-side code maintenance to handle data fetching and HTML generation for each request. | It focuses on client-side JavaScript code, which can be complex for highly interactive applications but simplifies server logic. |
Should you use SSR? You might not need it. You should consider using SSR if your project needs the following:
Should you use CSR? Consider CSR if your project prioritizes the following:
While SSR and CSR have strengths, sometimes a website or web app might have sections with conflicting needs or priorities. For example, while the blog section of a website might prioritize SEO and static content, the main news feed prioritizes real-time updates and user interaction. In such cases, a purely SSR or CSR approach might not be ideal for the entire application.
This is where hybrid approaches come into play. Hybrid approaches combine SSR and CSR techniques, rendering different parts of the application using the most suitable technique or method. This allows websites and web applications to leverage the strengths of both techniques, which, in the case of our previous example above, will improve SEO faster initial load time from SSR and enhance user experience and real-time updates from CSR.
Imagine an e-commerce website with a blog section and product pages. Content in the blog section is primarily static, focusing on SEO. SSR would be a good choice for this section; this is because pre-rendered HTML content from the server would ensure a faster initial load for users and better searchability by search engines.
On the other hand, the Product pages must have dynamic interactions like product filtering, adding items(products) to the carts, and user reviews. CSR shines here. Handling these interactions on the client side with Javascript makes the user experience smoother, with faster responses and fewer full-page reloads.
Frameworks like Next.js and Nuxt.js offer functionalities like selective rendering and code-splitting to facilitate these hybrid approaches. Selective rendering allows developers to choose which components are rendered on the server and which are fetched by the client-side JavaScript. Code-splitting further optimizes performance by loading only the necessary JavaScript code for each page section.
While hybrid approaches offer flexibility and performance boosts, it's important to acknowledge and notice the added complexity involved. Managing both server-side and client-side rendering techniques requires more development effort than using a single rendering technique. The decision to use a hybrid approach depends on the project's specific needs; thus, developers should be ready for the complexity it will introduce.
We have explored the two main techniques for rendering web pages: Server-Side Rendering (SSR) and Client-Side Rendering (CSR). SSR excels at delivering pre-rendered HTML content, which speeds up the initial load time and improves SEO. CSR shines in creating and crafting dynamic and interactive user experiences with real-time updates and dynamic content.
The decision to use either SSR or CSR will depend on your project's specific needs. SSR might be a better fit if SEO and initial load time are top priorities. However, the CSR approach is more appropriate for highly interactive applications or those requiring real-time updates.
Several frameworks, like React with Next.js or Vue.js with Nuxt.js, simplify working with SSR and CSR. These frameworks allow developers to optimize performance and user experience by combining the best of both rendering techniques.
When deciding between SSR and CSR, several factors can influence your choice.
Your project's specific needs play a significant role in selecting a rendering approach. If your site relies heavily on content that needs to be visible quickly, SSR might be beneficial. SSR can provide faster initial page loads and is ideal for content-heavy websites where SEO is a priority.
Consider the performance requirements of your audience. If users are on slower networks or low-powered devices, SSR can offer a better experience. Alternatively, if building a highly interactive or single-page application (SPA), CSR might be more suitable, enabling richer user experiences with smooth interactions after the initial load.
The skills and experience of your development team are important. Implementing CSR often requires proficiency in JavaScript frameworks like React or Angular. SSR might be more familiar to teams with experience in traditional server-side technologies.
Compatibility with your current technology stack is crucial. Modern frameworks like Next.js offer the flexibility to use both SSR and CSR. Integrating with a headless CMS like Strapi is feasible, allowing you to render pages effectively and improve content management. Headless CMSs are frontend agnostic, enabling developers to use any frontend framework for the presentation layer, supporting omnichannel content delivery and simplifying management with benefits like enhanced performance and scalability.
Consider future scalability and maintenance of your application. Frameworks supporting both SSR and CSR can offer flexibility as your project evolves.
Emore Ogheneyoma Lawrence is a Frontend React JS Developer and Technical Writer passionate about building user-centric products and contributing to open-source projects. He enjoys creating intuitive user interfaces and sharing his knowledge by writing about his learnings on his frontend developer journey.