What Is SSR — Server-Side Rendering Explained
In this tutorial, you will learn about What Is SSR. We cover key concepts, practical examples, and best practices to help you master this topic.
Server-Side Rendering (SSR) generates HTML on the server for each request, delivering fully-rendered pages to the browser for faster initial load, better SEO, and improved Core Web Vitals.
What You'll Learn
By the end of this tutorial, you will understand what server-side rendering is, how it differs from client-side rendering, the request-response cycle in SSR, the benefits and tradeoffs of SSR, and when to choose SSR over CSR or static generation.
Why It Matters
SSR solves two critical problems of client-rendered applications: slow initial page loads (users wait for JavaScript to download and execute) and poor SEO (search engines see empty HTML). SSR delivers ready-to-display HTML immediately, making it essential for content-driven web applications that need both interactivity and discoverability.
Real-World Use
A news website rebuilt as a React SPA saw their organic traffic drop 70 percent because search engines could not index their JavaScript-rendered content. After switching to Next.js SSR, their pages were indexed within hours, and organic traffic recovered within a month.
CSR vs SSR Request Flow
┌──────────────────────────────────────────────────────────┐
│ Client-Side Rendering (CSR) │
│ │
│ Browser Server API │
│ │ │ │ │
│ │ GET / │ │ │
│ │───────────────>│ │ │
│ │ Empty HTML │ │ │
│ │ (<div id=root>│ │ │
│ │<───────────────│ │ │
│ │ Load JS │ │ │
│ │─────────────────────────────────> GET data │
│ │<───────────────────────────────── JSON │
│ │ Render page │ │ │
│ │
├──────────────────────────────────────────────────────────┤
│ Server-Side Rendering (SSR) │
│ │
│ Browser Server API │
│ │ │ │ │
│ │ GET / │ │ │
│ │───────────────>│ │ │
│ │ │ GET data │ │
│ │ │──────────────>│ │
│ │ │<──────────────│ │
│ │ Full HTML │ Render HTML │ │
│ │<───────────────│ │ │
│ │ Show page │ │ │
│ │ (visible!) │ │ │
│ │ Load JS │ │ │
│ │ Hydrate │ │ │
└──────────────────────────────────────────────────────────┘
Think of CSR versus SSR like two different restaurant models. CSR is a meal kit delivery — you receive raw ingredients (JavaScript bundle) and must cook them yourself (execute JS) before eating (seeing content). SSR is a restaurant — the kitchen (server) prepares the complete dish (HTML) and serves it ready-to-eat. You can start eating immediately while the sauce (JavaScript) is added on the side.
SSR with a Basic Express Server
const express = require('express');
const React = require('react');
const { renderToString } = require('react-dom/server');
const App = require('./App');
const app = express();
app.get('/', async (req, res) => {
// 1. Fetch data on the server
const data = await fetchData();
// 2. Render React component to HTML string
const html = renderToString(
React.createElement(App, { data })
);
// 3. Send complete HTML to browser
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>SSR App</title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<div id="root">${html}</div>
<script id="__DATA__" type="application/json">
${JSON.stringify(data)}
</script>
<script src="/bundle.js"></script>
</body>
</html>
`);
});
app.listen(3000);
// Expected output in browser:
// HTML is fully rendered with content
// User sees the page immediately
// JavaScript loads and hydrates in background
// After hydration: page becomes interactive
SSR Benefits and Tradeoffs
const ssrAnalysis = {
benefits: {
seo: 'Search engines see complete HTML content immediately',
performance: 'Faster First Contentful Paint (FCP) and Largest Contentful Paint (LCP)',
accessibility: 'Content available even if JavaScript fails to load',
socialSharing: 'Social media crawlers see proper Open Graph metatags',
perceivedSpeed: 'Users see content while JavaScript loads in background'
},
tradeoffs: {
serverCost: 'Each request requires server processing time and resources',
complexity: 'Need to handle both server and client environments',
ttfb: 'Time to First Byte is slower because server renders on each request',
caching: 'Requires more sophisticated caching strategies than static sites',
hydration: 'JavaScript must still load for interactivity (hydration overhead)'
},
whenToUse: {
goodFor: [
'Content-driven applications (blogs, e-commerce, news)',
'Applications needing SEO',
'Pages with dynamic, user-specific content',
'Progressive Web Apps targeting Core Web Vitals'
],
avoidFor: [
'Simple static sites (use SSG instead)',
'Highly interactive real-time apps (consider SPA with SSR for initial load)',
'Pages with extremely high traffic and limited server budget'
]
}
};
Common Mistakes
- Treating SSR as a silver bullet. SSR improves initial load but adds server cost and complexity. For content that does not change often, static generation is simpler and faster.
- Hydration mismatch errors. The HTML rendered on the server must match what React renders on the client. Differences cause hydration errors. Ensure data Serialization and environment-specific code (window, document) are handled.
- Not handling asynchronous data on the server. Components that fetch data in useEffect or componentDidMount will not have data on the server. Fetch all required data before rendering.
- Sending too much JavaScript. SSR sends the initial HTML plus the full JavaScript bundle. Without Code Splitting, the user still downloads and executes the entire application JS.
- Ignoring server load. Each SSR request uses server CPU. Without Caching, a traffic spike can overwhelm the server. Implement caching and scale horizontally.
Practice Questions
- What is the main difference between CSR and SSR for initial page load?
- How does SSR improve SEO compared to client-side rendering?
- What is the time-tradeoff between TTFB and FCP in SSR?
- Why does SSR require handling both server and client environments?
- When would you choose SSR over SSG?
Challenge: Build a simple SSR application with Express and React (no framework). Create three routes that fetch data from a public API, render React components to HTML with renderToString, send complete HTML with embedded data, and hydrate on the client. Measure and compare CSR vs SSR load times.
FAQ
Mini Project
Build a simple blog with SSR using Express and React: three pages (home, blog listing, blog post) that fetch data from a JSON file, render React components to HTML with renderToString, send complete HTML with embedded data for hydration, add client-side hydration in the browser, and compare performance with a client-only version of the same app.
What's Next
You understand what SSR is. Now compare CSR vs SSR in detail to understand when to use each approach.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro