23 — SSR — When the Server Paints the First Frame
"A Next.js feature" was how I filed server-side rendering, which conflated the technique with the frameworks that sell it. The separation: rendering is a spectrum of _when_ and _where_ the HTML is generated, not a single technique. SSR is one point on that spectrum — the point where the server builds the HTML on each request, before the browser sees the page.
"Server-side rendering" gets used two ways: narrowly, a specific mode (per-request, on the server); broadly, the whole family of "let the server produce HTML instead of leaving it to the browser." Only the spectrum view makes the trade-offs legible, so that's where I start.
The spectrum: when and where HTML is born
Every page has to become HTML at _some_ point — the question is when, and on which machine. Four answers, and most production sites mix them [1][2]:
- CSR (Client-Side Rendering). The server ships a near-empty HTML shell plus a JS bundle. The browser downloads it, runs it, and the UI gets built in the browser. First paint is late and depends on JS executing.
- SSR (Server-Side Rendering). The server runs the component tree on _every request_ and returns finished HTML. The browser paints real content immediately; JS then "hydrates" it — attaches the interactive behavior to the already-rendered HTML — to make it interactive [3].
- SSG (Static Site Generation). HTML is rendered _once_, at build time. The server just hands out prebuilt files. Fast and cheap, but frozen until the next build.
- ISR (Incremental Static Regeneration). Build-time HTML the server revalidates on a schedule or on demand. Static speed with the freshness of SSR.
Same page, four different moments the HTML exists:
The shortcut I use now: CSR pushes the work onto the user's device and network; SSR (and its siblings) pull it back onto my server. The SEO, first-paint, and cost arguments are all consequences of that one shift.
Why SSR exists: content sooner, content crawlable
Two pressures pushed rendering back onto the server, and they're not the same problem.
First paint. Under pure CSR the browser receives an empty <div id="root"></div> and a script tag. The user stares at a blank screen until the JS downloads, parses, executes, fetches data, and writes to the DOM. On a slow phone that's a long, visibly empty wait. SSR shortens it: the HTML that comes back already _is_ the page, so the browser paints content on the first frame and hydrates it into an app afterward [3]. Interactivity still needs JS; the _content_ doesn't wait for it.
Crawlability. A search crawler historically had limited patience for running JavaScript [4]. Send it an empty shell and it may index exactly that — nothing. Send it rendered HTML and it reads headings, links, and text like a browser. That's why SSR is non-negotiable for content sites that depend on search traffic: the page has to _be_ something before any script runs.
So SSR trades one kind of cost for another. I give up the simplicity of a static bundle and the cheapness of a CDN-only deploy, and in return I take on a running server that has to render on every request. For a marketing site or a docs site, that trade is often a bad one and SSG wins. For a dashboard, an e-commerce catalog, or anything per-user and time-sensitive, SSR is what makes the page actually useful.
The trade-off, said plainly
SSR is not free, and the version I had in my head — "just turn it on, it's better" — was what needed correcting.
- Server load. Every request executes my component tree, often with data fetches. Real CPU on a real box, scaled with traffic. A viral spike under CSR mostly hits my CDN; under SSR it hits my render servers.
- Latency to first byte. The browser can't paint until the server finishes rendering. A slow database query _is_ a slow first byte now — under CSR that query happened after paint, in the browser.
- Complexity. Hydration has rules: server and client must agree on the output, or React warns about mismatches; window/document don't exist on the server; data fetching must resolve before render. A whole class of bugs CSR simply doesn't have.
- Caching is the whole game. Because every request _can_ render, the question is which _should_. SSG and ISR are SSR's answers to "render once" and "render sometimes" — choosing between them per-route is most of the real work.
SSR buys better first paint and real crawlability, and charges you server cost, TTFB (time to first byte) sensitivity, and a stricter way of thinking. Pick it where content is dynamic or SEO-critical; pick SSG/ISR where it isn't.
The frameworks that make it ergonomic
The technique predates all of them — PHP and Rails rendered HTML on the server before "SPA" (single-page application) was a word. What changed is that React, Vue, and Angular were born as _client_ renderers, and bringing them back to the server required real plumbing: a renderer that runs components in Node, a router that works on both ends, a data-fetching layer that resolves before render, and a hydration step on the client. That plumbing is what the meta-frameworks (frameworks built on top of a component library) package up.
Next.js (React). The one that pushed SSR-by-default into the mainstream for React, and the one this site is built on. Each route picks its rendering mode — SSR for a dashboard, SSG for a blog post, ISR for a list that revalidates on a tag. The App Router pushed the model further with React Server Components, where components run on the server by default and ship only the JS they need [5]. Next made "where does this render?" a per-route question.
Nuxt (Vue). Vue's answer to the same problem, and the symmetry with Next is deliberate — file-based routing, a Nitro server engine for Node or the edge (servers close to the user), and "hybrid rendering": a per-route config mixing SSR, SSG, ISR, and SPA in one app [6].
Angular (Universal). Took server rendering seriously earliest of the three, via Angular Universal — server-side rendering plus build-time prerendering [7]. Same spectrum; the framework's opinionated structure (DI — dependency injection, its way of handing components what they need — modules, templates) just makes the plumbing feel different.
TanStack Start (React). A newer React full-stack framework on TanStack Router, with SSR as a first-class default rather than a bolt-on [8]. The same bet the others are making — routing, server functions, data fetching, and rendering mode in one coherent layer — expressed with TanStack's primitives.
The pattern across all of them: the underlying component library (React, Vue, Angular) is the renderer; the meta-framework decides _when_ to call it and _where_, plus the plumbing — routing, data, hydration, caching. Once I saw it that way, "which framework should I learn" stopped being a question about SSR and became a question about my component library.
How I use this
The habit these notes left me with is a per-route question instead of a per-app one: _how dynamic is this content, and who needs to read it?_ Static and public (a blog post) → SSG. Static-ish with occasional updates (a project list) → ISR. Per-user or time-sensitive (a dashboard, a cart) → SSR. Interactive-only behind auth where SEO is irrelevant → CSR is honestly fine. SSR isn't the upgrade path I thought it was; it's one option on a slider.
References
[1] Mozilla, "Client-side rendering (CSR)," MDN Web Docs, 2024. [Online]. Available: https://developer.mozilla.org/en-US/docs/Glossary/CSR
[2] Vercel, "Rendering: The four rendering models," Next.js Learn, 2024. [Online]. Available: https://nextjs.org/learn/dashboard-app/rendering
[3] Mozilla, "Server-side rendering (SSR)," MDN Web Docs, 2024. [Online]. Available: https://developer.mozilla.org/en-US/docs/Glossary/SSR
[4] Google, "Understand how search works with JavaScript," Google Search Central documentation, 2024. [Online]. Available: https://developers.google.com/search/docs/crawling-indexing/javascript/javascript-seo-basics
[5] Vercel, "Rendering fundamentals," Next.js Documentation, 2024. [Online]. Available: https://nextjs.org/docs/app/building-your-application/rendering
[6] NuxtLabs, "Rendering modes," Nuxt Documentation, 2024. [Online]. Available: https://nuxt.com/docs/guide/concepts/rendering
[7] Angular Team, "Server-side rendering (SSR) with Angular," Angular Documentation, 2024. [Online]. Available: https://angular.dev/guide/ssr
[8] TanStack, "TanStack Start overview," TanStack Documentation, 2025. [Online]. Available: https://tanstack.com/start/latest/docs/framework/react/overview
Knowledge check · Question 1 of 5
Under pure CSR, what does the browser receive on the first request?
Comments
Leave a Comment
You must be signed in to comment
0 Comments
No comments yet. Be the first to comment!