Web & Frontend Development

Frontend Rendering Strategies: A Practical Guide to CSR, SSR, SSG, and Beyond

"Should this be server-rendered?" is one of the most consequential questions a frontend team answers, and one of the most likely to be settled by habit rather than reasoning. The rendering strategy you pick decides how fast the first screen appears, how fresh the data is, how much your servers do, and how well the page works for crawlers and screen readers. Pick the wrong one and you either ship a blank white screen that waits on JavaScript, or you pay to server-render a page that never needed it.

The short version: rendering strategy is a per-route decision, not a per-app one. Match each route to what it actually needs — static when content rarely changes, server-rendered when it's dynamic and SEO matters, client-rendered for private app shells behind a login — and stop treating any single approach as the default.

What "rendering" actually decides

Rendering is the process of turning your components and data into HTML the browser can paint. The question is where and when that happens: in the browser at request time, on the server at request time, or at build time well before any user shows up. That single choice cascades into the metrics users feel.

The cascade is what matters. Where you render drives how quickly the user sees content (first paint), how quickly they can interact with it (time to interactive), how current the data is, and how much work the browser has to redo to make a server-sent page interactive. Every strategy below is a different point on those trade-offs — there's no free lunch, only a choice about which cost you'd rather pay.

Client-side rendering (CSR)

With CSR, the server sends a near-empty HTML shell and a JavaScript bundle. The browser downloads the bundle, runs it, fetches data, and builds the page in place.

<!-- What the server sends with CSR -->
<div id="root"></div>
<script src="/bundle.js"></script>

CSR shines for highly interactive apps behind authentication — dashboards, editors, internal tools — where there's no SEO requirement and the user is already committed enough to wait a moment for the app to boot. After that initial load, navigation is fast because it happens client-side without round-trips.

The cost is the first load. The user stares at a blank or skeleton screen until JavaScript downloads, parses, and runs, and a crawler that doesn't execute JavaScript well sees almost nothing. On a slow device or network, "time to first meaningful content" can be genuinely bad. Reach for CSR when discoverability doesn't matter and interactivity does.

Server-side rendering (SSR)

With SSR, the server runs your components on each request, fetches the data, and returns fully-formed HTML. The browser paints real content immediately, then hydrates — attaching event listeners to make the static markup interactive.

SSR is the right call when content is dynamic and must be visible to crawlers and fast on first view: think product pages with live pricing, personalized landing pages, or anything where a user lands cold from search. The first paint is fast and the page is accessible and indexable before any JavaScript runs.

The trade-offs are real and worth naming. You now run a server (or serverless function) for every request, which costs compute and adds latency you control through your data fetching. And hydration isn't free — the browser re-runs much of the same component work to wire up interactivity, which can delay time-to-interactive even though the page looks ready. A page that paints in 200ms but isn't clickable for two seconds frustrates users in a specific, measurable way.

Static site generation (SSG)

SSG renders pages to HTML at build time. The output is plain files you can serve from a CDN, with no per-request server work at all.

build  /index.html /blog/post-1.html /blog/post-2.html  deploy to CDN

For content that's the same for every visitor and changes infrequently — marketing pages, documentation, blog posts — SSG is hard to beat. It's the fastest possible first paint (a CDN serving a file), the cheapest to run, and the most resilient, because there's no runtime to fall over. It's also excellent for SEO since the HTML is complete and instant.

The limit is freshness and scale. Anything personalized or real-time can't be baked in ahead of time, and if you have hundreds of thousands of pages, build times grow until full rebuilds become painful. SSG is the default to reach for first whenever content allows it, precisely because it pushes the most work to build time where it's cheapest.

Incremental and hybrid approaches

The line between "static" and "dynamic" stopped being binary, and the in-between options solve the freshness problem without giving up static's speed.

  • Incremental Static Regeneration (ISR) serves a cached static page but re-generates it in the background on a schedule or on demand. You get static speed with data that's "fresh enough," which suits catalogs and content that updates hourly rather than per-request.
  • Streaming SSR sends HTML in chunks as it's ready, so the shell and above-the-fold content paint while slower data still loads. It improves perceived performance for SSR pages with one slow data dependency.
  • Partial hydration / islands ship JavaScript only for the interactive parts of a page and leave the rest as static HTML. This directly attacks hydration cost — most marketing pages are mostly static content with a few interactive widgets, and there's no reason to hydrate the whole tree.
  • React Server Components push the static/dynamic split into the component model itself, rendering some components only on the server and sending no JavaScript for them.

None of these is a silver bullet. They're tools for the specific problem of "I want static-level performance but some of this needs to be dynamic or interactive."

How to choose: decide per route

The most useful reframe is to stop asking "which framework rendering mode should my app use?" and start asking it one route at a time. A single application can, and usually should, mix strategies.

Walk each route through three questions:

  1. Does it need to be indexed or fast on first view for an anonymous user? If no (it's behind a login), CSR is on the table. If yes, the page needs real HTML on first response — SSR or SSG.
  2. Is the content the same for everyone and stable between deploys? If yes, SSG (or ISR if it changes periodically). If it's personalized or real-time, SSR.
  3. How fresh must the data be? Per-request fresh → SSR. Fresh within minutes or hours → ISR. Fresh per build → SSG.

A concrete example: an e-commerce site might statically generate its marketing and category pages (SSG), regenerate product pages periodically for price updates (ISR), server-render search results and personalized recommendations (SSR), and client-render the logged-in account dashboard (CSR). Each route gets the cheapest strategy that meets its actual requirement. All of these still depend on a well-designed data layer underneath — your rendering choice only controls where you call the API, not whether that API is modeled cleanly.

Measure with Core Web Vitals, not vibes

Whatever you pick, validate it against what users feel, not what feels modern. The field metrics worth watching are Largest Contentful Paint (how fast the main content appears), Interaction to Next Paint (how responsive the page feels to input — where excess hydration shows up), and Cumulative Layout Shift (whether content jumps around as it loads). Measure these on real devices and real networks; a rendering strategy that wins on your developer laptop can lose badly on a mid-range phone, which is what most of your users are actually holding.

A rendering decision checklist

  1. Default to static (SSG) for content that's the same for everyone and changes rarely.
  2. Use SSR when content is dynamic and must be indexable or fast on first view.
  3. Use CSR for interactive, authenticated app shells with no SEO need.
  4. Reach for ISR/streaming/islands to close specific gaps — freshness, slow data, hydration cost — not by default.
  5. Decide per route, and let one app mix strategies.
  6. Verify with field Core Web Vitals on real devices before calling it done.

FAQ

Is server-side rendering always better for SEO?

Not always — it's better than CSR for SEO because crawlers get complete HTML immediately, but SSG gives the same indexability with better performance and lower cost when the content is static. The SEO win comes from sending real HTML on first response; both SSR and SSG do that, so choose between them on freshness and scale, not SEO alone.

What exactly is hydration, and why is it a problem?

Hydration is the browser re-running your components over server-rendered HTML to attach event handlers and make it interactive. It's "a problem" only in that it duplicates work: the page can look ready while still being unclickable, hurting Interaction to Next Paint. Partial hydration and islands exist to ship less of it.

Do I need a meta-framework to do SSR or SSG?

No, but one helps. You can implement any of these strategies by hand, but frameworks that support per-route rendering remove a large amount of routing, data-fetching, and build wiring. The strategies in this guide are concepts; the framework is just the tool that makes mixing them ergonomic.

Is client-side rendering obsolete now?

No. CSR is still the right choice for authenticated, highly interactive applications where SEO is irrelevant and fast post-load navigation matters more than first paint. It became a poor default for content sites, which is different from being obsolete.

How do I pick if a route's needs are borderline?

Default to the cheaper, more resilient option and only escalate when a requirement forces it. Start static, move to ISR when freshness demands it, and move to SSR only when the data is genuinely per-request or personalized. Escalating on evidence beats over-engineering on speculation.

Next step

Open your analytics, find your slowest or least-discoverable route, and run it through the three questions above. Decide what it actually needs — fresh data, fast first paint, or just interactivity behind a login — and move it to the strategy that matches. Fixing rendering one route at a time, measured against real Core Web Vitals, is how a frontend gets fast without a rewrite. See more engineering guides at TheAppCode.

Comments are disabled for this article.