---
title: Server-Side Rendering
description: A rendering strategy where the server generates full HTML for every request, giving the browser a complete page to display immediately.
tokens: ~616
---

# Server-Side Rendering

The server executes the application code on each request, produces a complete HTML document, and sends it to the browser. The user sees content as soon as the HTML arrives — no waiting for JavaScript to build the page. After the initial paint, the browser downloads JS and **hydrates** the page: it attaches event listeners and makes the static HTML interactive.

## How It Works

```
┌──────────┐         ┌──────────┐
│  Server  │         │ Browser  │
└────┬─────┘         └────┬─────┘
     │←──── request ──────│
     │                    │
     │  full HTML+<script>│
     │───────────────────→│
     │                    │  paint (visible)
     │                    │  download JS
     │                    │  hydrate
```

The gap between content being visible (FCP) and the page becoming interactive (TTI) is the **hydration cost**. During this window, the page looks ready but buttons and inputs may not respond yet.

## React API

React provides `renderToString` (blocking) and `renderToPipeableStream` (streaming, covered in [Streaming SSR](/docs/web/rendering/streaming)):

```typescript
import { renderToString } from "react-dom/server";
import { App } from "./App";

function handleRequest(req: Request): Response {
  const html = renderToString(<App url={req.url} />);

  return new Response(
    `<!doctype html>
    <html>
      <body>
        <div id="root">${html}</div>
        <script src="/client.js"></script>
      </body>
    </html>`,
    { headers: { "content-type": "text/html" } },
  );
}
```

On the client, `hydrateRoot` reuses the existing DOM instead of recreating it:

```typescript
import { hydrateRoot } from "react-dom/client";
import { App } from "./App";

hydrateRoot(document.getElementById("root")!, <App url={location.pathname} />);
```

SSR is a good default for pages that need fast first paint and search-engine visibility.

## Trade-offs

| Strength                                       | Weakness                                                       |
| ---------------------------------------------- | -------------------------------------------------------------- |
| Fast FCP — complete HTML in the first response | TTFB depends on data-fetching time; slow APIs delay everything |
| Strong SEO — crawlers receive full HTML        | Higher server cost — every request requires CPU to render      |
| Works for dynamic, per-request content         | Hydration gap — page looks ready before it actually is         |