Server Rendering
SSR, static generation and incremental rendering, server components, and loading data — why a meta-framework exists at all.
Why Render on the Server At All
Server rendering sends real HTML. The user sees content on the first response instead of after a round of downloading and executing, and a crawler gets a page rather than an empty shell.
The page then hydrates: the same components run in the browser and attach their event handlers to markup that already exists. Between arrival and hydration the page looks ready but does not respond — a real gap, and a large bundle widens it.
This is most of what a meta-framework is for. Routing, data loading, bundling and the server and client halves of rendering are hard to wire together correctly, and the framework has made those decisions already.
SSR, SSG & Incremental Rendering
The real question is when the HTML is produced. Everything else follows from that answer.
| Mode | HTML is built | Fits | Cost |
|---|---|---|---|
| CSR | In the browser, after JS loads | Dashboards behind a login | Blank first paint, poor for crawlers |
| SSR | Per request, on the server | Personalised or fast-changing pages | Server cost and latency on every hit |
| SSG | At build time | Docs, marketing, blogs | Stale until you rebuild |
| ISR | At build, then refreshed in the background | Catalogues that change sometimes | A window where content is stale |
Prefer the earliest one that works. Static HTML from a CDN is the fastest and cheapest thing on the web; per-request rendering is the most flexible and the most expensive. Incremental regeneration is the middle: serve the cached page, rebuild it behind the scenes when it ages out.
Server Components
A server component runs only on the server and never ships to the browser. Its output is sent as rendered markup, so the code — and any dependency it used — stays out of the bundle entirely.
That is the appeal: a component that formats dates with a large library adds nothing to what the user downloads. Data fetching can also happen directly inside it, with no API round trip from the client.
| Server component | Client component | |
|---|---|---|
| Ships JS to the browser | No | Yes |
| State and effects | No | Yes |
| Event handlers | No | Yes |
| Direct database access | Yes | No |
| Browser APIs | No | Yes |
The two compose: server components render the static shell and pass data down; client components handle anything interactive. Push the boundary as deep as you can — a single interactive button should not make its whole page a client component.
API Routes & Data Loading
With rendering on the server, data loading moves there too — fetch during render rather than after mount, and the HTML arrives complete instead of arriving empty and filling in.
The failure to watch for is the waterfall: a parent awaits its data, then renders a child that awaits its own. Two sequential round trips where one would do. Start independent requests together and await them together.
| Situation | Do |
|---|---|
| Several independent fetches | Start them in parallel, await once |
| One slow section | Stream it behind a Suspense boundary |
| Data that rarely changes | Cache it; revalidate on a timer |
| A user action changing data | Mutate on the server, then revalidate |
| Anything secret | Keep it server-side; never send it down |
A meta-framework also gives you API routes — server endpoints living beside the pages. Useful for webhooks, form handling and anything needing a key you cannot expose, without standing up a separate service.
Interview Questions
SSR versus SSG — how do you choose?
By when the HTML can be built. If the page is the same for everyone and changes rarely, build it once at deploy and serve it from a CDN. If it is personalised or changes constantly, render per request and pay the server cost. Incremental regeneration sits between them.
What is hydration, and what goes wrong with it?
The client re-runs the components and attaches handlers to server-rendered markup. Between paint and hydration the page looks interactive but is not, and a large bundle widens that gap. A mismatch between server and client output also forces a re-render and can flash.
What does a server component actually save?
Bundle size and a round trip. The component and its dependencies never reach the browser, and it can read data directly instead of calling an API. The trade is no state, no effects, no event handlers.
What is a data waterfall?
Sequential fetches that could have been parallel — a parent awaits, then renders a child that awaits. Each layer adds a full round trip. Start independent requests together.
Why not render everything on the server?
Anything interactive needs client JavaScript, and per-request rendering costs server time and latency on every hit. The aim is the smallest client bundle that still delivers the interactivity the page needs.