SSR generates HTML on the server for each request and ships it to the browser ready to display — here is how it compares to SSG, CSR, and ISR, and which one your SaaS should actually use.
Research-based overview. This article synthesizes public documentation, framework release notes, and developer reports. How we research.
The phrase “server-side rendering” tends to confuse people because it competes with three other terms that all sound similar — SSG, CSR, and ISR — and frameworks like Next.js have spent the last few years quietly redefining what each one means. The version that matters in 2026: SSR is one of four rendering modes a modern React framework can choose from, and the choice shapes how fast the page feels, how it ranks in search, how much you pay for compute, and how complicated the codebase becomes.
For a solo SaaS founder, the practical question is rarely “what is SSR?” in the abstract. It is “which rendering mode should I use for which page?” The answer is almost always a mix, and the modern Next.js App Router has changed the mental model from “pick a mode per page” to “let components run where they make sense.” Before getting to that, the four-mode taxonomy is still the cleanest way to think about it.
Every modern React framework supports some combination of these four. They are not mutually exclusive — a single application typically uses two or three of them across different routes.
The server returns a near-empty HTML shell with a <div id="root"></div> and a JavaScript bundle. The browser downloads the bundle, executes React, fetches data, and renders the page. This is the original Single Page Application pattern popularized by Create React App and tools like Vite's React template.
The user sees a blank page until the JavaScript finishes loading and rendering. Search engines that do not execute JavaScript see nothing at all — the HTML payload is essentially empty. CSR is fast on subsequent navigations because the JavaScript framework already lives in memory and only fetches data, but the first paint is the slowest of the four modes.
Best for: dashboards behind a login wall where SEO is irrelevant and the user already paid the bundle-load cost on sign-in.
The server runs React on every request, builds the full HTML for the requested page, and sends it back to the browser. The HTML contains the actual content the user is going to see — product names, pricing, the user's name from a session lookup, today's data from a database query — before any JavaScript runs.
The browser displays the page immediately. JavaScript still loads in the background to make the page interactive (the “hydration” step), but the user sees content much faster than with CSR. Search engines see fully-rendered HTML. The trade-off is that the server does work on every request, so Time to First Byte (TTFB) is slower than serving a static file, and your origin pays for that compute.
Best for: pages with personalized content per user, real-time data, or anything that changes more often than you want to redeploy.
The framework runs React once at build time, generates HTML files for every page, and writes them to disk. The deployment is a folder of static HTML, CSS, and JavaScript that any CDN can serve in single-digit milliseconds. There is no per-request compute — the page is already a file.
SSG produces the fastest possible TTFB and the cheapest hosting bill. The downside: the content is frozen at build time. If you want to update a blog post, you have to redeploy. If you have a product page that depends on inventory levels, the page is wrong until the next deploy. SSG is perfect for content that changes on the order of days or weeks, terrible for content that changes per request.
Best for: marketing pages, blog posts, documentation, glossary entries like this one, anything where the content does not vary by user.
ISR is SSG with a cache invalidation hook. The framework still generates static HTML at build time, but each page has a TTL (time-to-live) after which it is considered stale. On the first request after the TTL expires, the framework regenerates the page in the background and serves the stale version to the current user. The next user gets the fresh version.
This is the Next.js innovation that made “static” sites feel dynamic. A blog post can be regenerated every hour without a redeploy. A product catalog can be statically rendered but stay roughly current. The trade-offs of SSG without the rigidity. ISR can also be triggered on-demand via Next.js's revalidatePath() function, which means a content edit in a CMS can purge the relevant cached pages immediately.
Best for: content that updates predictably (every hour, every day) but does not need to be live-fresh per request.
The link between SSR and React in the browser is hydration. The server sends fully-rendered HTML; the browser parses and displays it; then the React JavaScript bundle loads and React walks the DOM, attaching event handlers and reconciling its virtual DOM with the real one. After hydration, the page is interactive. Before hydration, it is just text and images — clicks do nothing.
The hydration mismatch bug happens when the HTML React generates on the server differs from what it would generate on the client. Common causes include rendering new Date().toLocaleString() (timezone differs), reading window.innerWidth (undefined on the server), or anything that depends on a value the server cannot know. React notices the mismatch, throws a warning, and re-renders the affected subtree from scratch — you lose the SSR benefit and may briefly flash the wrong content.
The fix is to defer client-only rendering with useEffect or to mark a component as client-only via the 'use client' directive in the App Router. Hydration mismatches are the most common SSR bug, and the React team has spent considerable effort making them less brittle in React 19, but they still happen.
| Mode | SEO | TTFB | Personalization | Server cost |
|---|---|---|---|---|
| CSR | Poor (empty HTML) | Fast (static shell) | Yes, after JS loads | Low (static file + API) |
| SSR | Excellent | Slower (server runs per request) | Excellent | High (compute per request) |
| SSG | Excellent | Fastest (file from CDN) | None (build-time only) | Lowest |
| ISR | Excellent | Fast (file from CDN) | Limited (per-segment, not per-user) | Low (occasional regeneration) |
The core trade-off is between freshness, personalization, and cost. You cannot have all three at maximum. SSG buys you free hosting at the cost of staleness; SSR buys you per-request freshness at the cost of compute; ISR splits the difference for content that does not need per-user personalization; CSR pushes the work to the client and buys you cheap hosting at the cost of search visibility and perceived speed.
SSR is the right answer when the page content is unique to the requesting user and the user expects to see it immediately. The canonical examples:
For everything that does not change per user, SSG (or ISR if it changes occasionally) is the better default. The list is bigger than most people expect:
CSR is rarely the right default in 2026, but it has a few legitimate niches:
The Next.js App Router shipped stable in 2023 and has become the default for new Next.js apps. It changes the mental model in a way that matters: instead of picking a rendering mode per page, you write components that are server components by default and mark the ones that need to run in the browser with 'use client'. The framework figures out where each component runs.
A page in the App Router is typically a tree of server components (running on the server, rendering once, no JavaScript shipped to the browser) with islands of client components (interactive, hydrated, JavaScript shipped). The server components fetch data, render HTML, and stream it. The client components hydrate into interactive widgets. The bundle size shrinks dramatically because only the interactive parts ship to the browser.
Inside this model, the four classic modes still exist as configuration choices on a route:
export const dynamic = 'force-static' — SSG behavior. Generated at build time.export const dynamic = 'force-dynamic' — SSR behavior. Rendered per request.export const revalidate = 3600 — ISR behavior. Regenerated hourly.'use client' directive at the top still SSRs initially, then hydrates — CSR behavior on subsequent navigations.The new defaults are sensible: pages without explicit dynamic data sources are statically rendered; pages that read cookies, headers, or use searchParams automatically opt into dynamic SSR. The framework chooses for you in the common case.
One of the most underrated features of modern SSR is streaming. Instead of waiting for the entire page to render on the server before sending any HTML, the server can stream the HTML in chunks as parts of the page become ready. The user sees the navigation and the page shell immediately; slower components show a fallback (a spinner, a skeleton) until their data resolves; the server pushes the rendered component down the wire when it is ready.
The mechanism is React Suspense plus the App Router's built-in streaming support. You wrap a slow component in <Suspense fallback={...}> and the rest of the page renders without waiting for it. The numbers matter: a page that takes 800ms to render fully can stream the shell in 100ms and finish the slow parts later, dramatically improving perceived performance and Core Web Vitals scores.
Traditional SSR runs in a centralized region — AWS us-east-1 is the canonical default. Users far from that region pay the round-trip latency on every request. Edge SSR runs the same server code on edge nodes scattered across the globe, often on platforms like Cloudflare Workers or Vercel Edge Functions, so the per-request rendering happens within ~30ms of the user.
The catch is the runtime constraints. Edge functions typically run on a Web Workers-style runtime with limited Node API surface — no native fs, no native database drivers, no long-running connections. Database queries usually go through HTTP-based clients like the Neon serverless driver or Supabase's REST API. For SaaS apps with light data dependencies and global audiences, edge SSR is genuinely faster than centralized SSR. For apps that pull large quantities of data from a Postgres database in a specific region, edge SSR can actually be slower because the database round-trip is longer than the saved network distance.
Most solo founders should default to centralized SSR (the Node.js runtime in Next.js terms) and migrate specific routes to edge if and when latency becomes a measurable problem. The breakdown in Vercel vs Cloudflare Pages walks through how the two platforms approach this trade-off.
For a solo founder shipping a SaaS in 2026, the answer is straightforward: use Next.js App Router, let the framework default to React Server Components plus streaming, and do not overthink the rendering mode for each route. The framework picks well by default.
Rough decision rules:
The rendering-mode debate of 2018–2022 mostly settled itself: modern frameworks support all four modes, and the right answer for almost any solo SaaS is to use the right mode for the right route inside one Next.js app. Once the deployment platform is picked — see our notes on deploying Next.js to Vercel and the broader Next.js vs Remix comparison — the rendering-mode choice tends to make itself. Layer in Vercel cron jobs for scheduled work and a CDN-fronted edge cache, and the architecture story is essentially done.
Server-side rendering is the rendering mode where HTML is generated on the server per request and hydrated into a React app on the client. It is one of four common modes — CSR, SSR, SSG, ISR — that modern frameworks let you mix in a single application. The Next.js App Router has reframed the choice from “pick a mode per page” to “write components that run where they make sense,” which is the right level of abstraction for a solo founder. Default to SSG/ISR for content that does not change per user, default to SSR for everything behind authentication, treat CSR as a niche tool, and let the framework do the rest.
The stack, prompts, pricing, and mistakes to avoid — for solo founders building with AI.