Server-Side Rendering
Server-side rendering means React renders the initial UI on the server and sends HTML to the browser.
The browser can display content quickly, then React hydrates the HTML to make it interactive.
The SSR Request Flow
browser requests /products/42
|
v
server loads route and data
|
v
React renders HTML
|
v
server sends HTML response
|
v
browser displays content
|
v
JavaScript loads and hydratesThe exact APIs depend on the framework, but the shape is similar.
What the Server Produces
The server sends HTML that already contains page content.
<main>
<h1>Noise-Canceling Headphones</h1>
<p>$199</p>
<button>Add to cart</button>
</main>Before hydration, the user can read the content. The button may not work yet.
After hydration, React attaches event handlers and manages updates.
Data Fetching on the Server
SSR often fetches data before rendering.
async function ProductPage({ productId }) {
const product = await getProduct(productId);
return (
<main>
<h1>{product.name}</h1>
<p>${product.price}</p>
</main>
);
}Server data fetching can keep secrets off the client. For example, database credentials and private API keys should stay on the server.
Benefits
SSR can improve:
- first meaningful content
- SEO for public content
- social link previews
- slow-device startup experience
- access to server-only data sources
It can also reduce client-side loading waterfalls when the server fetches critical data before sending the page.
Costs
SSR introduces tradeoffs:
- every uncached request may use server CPU
- slow backend calls delay the HTML response
- personalized pages can be hard to cache
- hydration still requires client JavaScript
- server and browser environments differ
You need to measure both server response time and client hydration time.
Environment Differences
Server code does not have browser-only globals.
function BadTheme() {
const theme = localStorage.getItem("theme"); // localStorage is not available on the server
return <p>{theme}</p>;
}Move browser-only reads into an effect or pass the value from a safe source.
function ThemeLabel() {
const [theme, setTheme] = useState("system");
useEffect(() => {
setTheme(localStorage.getItem("theme") || "system");
}, []);
return <p>{theme}</p>;
}This avoids a server crash, but it may briefly show the fallback value.
Security Awareness
SSR can access privileged data, so keep boundaries clear.
Do not serialize secrets into HTML.
<script>
window.__CONFIG__ = { apiKey: "private-secret" };
</script>Anything sent to the browser is public to the user.
Streaming Awareness
Modern React servers can stream HTML in chunks.
send shell
-> stream header and layout
-> stream fast content
-> stream slower sections when readyStreaming can improve perceived speed because the browser can start rendering before all data is ready.
Frameworks decide how streaming is exposed, but the principle is important: SSR does not have to be one all-or-nothing response.
Common Mistakes
- Reading
window,document, orlocalStorageduring server render. - Fetching many resources sequentially and creating slow server waterfalls.
- Sending private data in serialized page state.
- Ignoring hydration cost after improving HTML response time.
- Assuming server-rendered HTML means every control is immediately interactive.
Which value is safe to expose in SSR HTML?
Practical Challenge
Design an SSR product page.
List:
- which data must be fetched before rendering
- which data can load later on the client
- what can be cached
- what must never be serialized into HTML
Recap
SSR sends meaningful HTML from the server, but interactivity still depends on client JavaScript and hydration.
Good SSR design balances first content, server latency, caching, hydration cost, and security boundaries.