---
term: 'SSR vs. CSR vs. SSG'
seoTitle: 'SSR vs. CSR vs. SSG: Rendering Patterns, SEO, Metrics'
headline: 'SSR vs. CSR vs. SSG: how web rendering works'
slug: ssr-vs-csr-vs-ssg
category: frontend-web
shortDefinition: 'SSR vs. CSR vs. SSG is a comparison of rendering strategies by where and when HTML is generated: build time, server, or browser.'
relatedTerms:
  - jamstack
  - cdn-content-delivery-network
  - progressive-web-app-pwa
  - api
contrastsWith:
  - jamstack
aboutTerms:
  - 'Hydration'
  - 'ISR & Streaming'
  - 'TTFB / FCP / TTI'
faq:
  - question: 'What is CSR (client-side rendering)?'
    answer: 'The server sends a near-empty HTML shell plus a JavaScript bundle; the browser downloads, parses, and runs the JS, fetches data from an API, and builds the page. The user sees a blank screen or spinner until the JavaScript executes — best interactivity, worst initial load and SEO.'
  - question: 'What is SSR (server-side rendering)?'
    answer: 'The server generates complete HTML for each request — running code and fetching data — and sends a ready-to-paint document, then hydrates it for interactivity. Strong SEO and fast first paint with always-fresh data, at the cost of server compute and a higher time-to-first-byte.'
  - question: 'What is SSG (static site generation)?'
    answer: 'HTML for every page is prebuilt at build time into static files and served from a CDN, with no per-request server work. The fastest, cheapest, and most SEO-friendly option — but the data is only as fresh as the last build, and it fits poorly for unknown or highly dynamic routes.'
  - question: 'What is the difference between them?'
    answer: 'Where and when the HTML is generated: at build time (SSG), on the server per request (SSR), or in the browser at runtime (CSR). Everything else — SEO, performance, data freshness, cost — follows from that one choice.'
  - question: 'Which rendering strategy is best for SEO?'
    answer: 'SSG and SSR, because crawlers receive fully formed HTML. CSR is riskiest, since bots must execute JavaScript to see the content, which delays or can cost indexing. The nuance: modern crawlers do render JavaScript, but with a budget — so CSR is fine for non-indexable surfaces and a gamble for content that must rank.'
  - question: 'What is hydration?'
    answer: 'Attaching JavaScript — event listeners and state — to already-rendered server HTML so a static-looking page becomes interactive. The catch: the JS still has to download, parse, and execute, so a page can look ready while remaining unclickable, delaying time-to-interactive even when first paint was fast.'
  - question: 'What is ISR (incremental static regeneration)?'
    answer: 'A hybrid that serves static pages but regenerates individual ones in the background on a revalidation interval or on demand, combining SSG''s speed with fresher data. Visitors may see a slightly stale page until the regeneration completes.'
  - question: 'When should you use SSR versus SSG?'
    answer: 'SSG for content that is the same for everyone and changes rarely — docs, blogs, marketing. SSR for pages that are personalized, authentication-gated, or change frequently enough that build-time data would be stale. The default advice: prefer SSG, and reach for SSR only where per-request freshness is required.'
  - question: 'Do single-page apps hurt SEO?'
    answer: 'They can — content that depends on JavaScript execution delays or blocks indexing. It is fine for dashboards and internal tools that don''t need to rank, but content meant for search should be server-rendered or statically generated so crawlers see it immediately.'
  - question: 'Is it one strategy per app?'
    answer: 'No — the modern practice is per-route, even per-component: static marketing pages, regenerated catalog pages, server-rendered dashboards, and client-rendered widgets can all live in one app. Rendering is a decision you make per page, not once for the whole site.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'Client-side rendering (CSR) — MDN Web Docs'
    url: 'https://developer.mozilla.org/en-US/docs/Glossary/CSR'
  - name: 'Server-side rendering (SSR) — MDN Web Docs'
    url: 'https://developer.mozilla.org/en-US/docs/Glossary/SSR'
  - name: 'Rendering patterns — patterns.dev'
    url: 'https://www.patterns.dev/'
  - name: 'Static site generator — Wikipedia'
    url: 'https://en.wikipedia.org/wiki/Static_site_generator'
cta:
  title: 'One API, any rendering strategy'
  text: 'Back4app''s REST and GraphQL APIs feed SSG at build, SSR per request, and CSR in the browser unchanged — pick your rendering per route; the backend stays the same.'
  linkText: 'Start building free'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-07-30'
translationKey: ssr-vs-csr-vs-ssg
---

**SSR vs. CSR vs. SSG is a comparison of rendering strategies by where and when HTML is generated: build time, server, or browser.** That single axis — *where and when* — determines SEO, performance, data freshness, and cost; everything else is downstream of it. And the backend-developer's clarification the frontend guides bury: **rendering is a frontend concern; the data is a backend one.** All three strategies call the same [API](/glossary/api/); they differ only in the moment they call it.

## Key takeaways

| Question | Answer |
| --- | --- |
| The axis | *Where and when* HTML is made — build · server · browser |
| CSR | Browser builds it — best interactivity, worst first load & SEO |
| SSR | Server builds it per request — fresh, SEO-strong, higher TTFB |
| SSG | Prebuilt at build, [CDN](/glossary/cdn-content-delivery-network/)-served — fastest, cheapest, stale-until-rebuild |
| The reframe | Same [API](/glossary/api/), three call times — it's per-route, not per-app |

## Same data, three call times

**JavaScript:**

```javascript
// JavaScript — the SAME API call, consumed three ways.
// Rendering is a FRONTEND choice; the data is a BACKEND concern.
async function getPosts() {
  const q = new Parse.Query('Post').equalTo('published', true).limit(20);
  return q.find(); // one backend endpoint — the ONLY thing that changes is WHEN
}

// SSG — called at BUILD time; data baked into static HTML, served from a CDN.
// SSR — called PER REQUEST on the server; fresh HTML sent to the browser.
// CSR — called FROM THE BROWSER after load; the client builds the DOM.
// You don't change the backend to switch rendering — only when/where you fetch.
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// Whatever the rendering strategy, the data comes from one backend API.
Future<List<ParseObject>> getPosts() async {
  final q = QueryBuilder<ParseObject>(ParseObject('Post'))
    ..whereEqualTo('published', true)
    ..setLimit(20);
  return (await q.query()).results?.cast<ParseObject>() ?? [];
}
// SSG fetches at build, SSR fetches per request, CSR fetches in the client —
// the endpoint is identical; only the timing and location differ.
```

**Swift:**

```swift
// Swift — Back4app Swift SDK
// Whatever the rendering strategy, the data comes from one backend API.
func getPosts() async throws -> [Post] {
    try await Post.query("published" == true).limit(20).find()
}
// SSG fetches at build, SSR fetches per request, CSR fetches in the client —
// the endpoint is identical; only the timing and location differ.
```

**Kotlin:**

```kotlin
// Kotlin — Back4app Android SDK
// Whatever the rendering strategy, the data comes from one backend API.
fun getPosts(): List<ParseObject> {
    val q = ParseQuery.getQuery<ParseObject>("Post")
    q.whereEqualTo("published", true)
    q.limit = 20
    return q.find()
}
// SSG fetches at build, SSR fetches per request, CSR fetches in the client —
// the endpoint is identical; only the timing and location differ.
```

One `getPosts()`, one backend endpoint. **SSG** calls it at *build time* and bakes the result into static HTML; **SSR** calls it *per request on the server* and sends fresh HTML; **CSR** calls it *from the browser* after load. You never change the backend to change rendering — only the moment and the place you fetch. That's the fact that turns a confusing three-way comparison into one decision.

## SSR vs. CSR vs. SSG, side by side

```mermaid
flowchart LR
  accTitle: Where HTML is generated in CSR, SSR, and SSG
  accDescr: In client-side rendering, the server sends an empty shell and a JavaScript bundle, and the browser fetches data from the API and builds the page. In server-side rendering, the server fetches from the API per request and sends complete HTML that is then hydrated. In static site generation, HTML is prebuilt from the API at build time and served from a CDN. All three read the same backend API.
  API[("Backend API")] -->|"at build time"| SSG["SSG → static HTML → CDN"]
  API -->|"per request, server"| SSR["SSR → full HTML → hydrate"]
  API -->|"from the browser"| CSR["CSR → shell + JS → build DOM"]
```

| | CSR | SSR | SSG |
| --- | --- | --- | --- |
| HTML generated | In the browser | Server, per request | At build time |
| TTFB | Fast | **Higher** (renders first) | **Fastest, consistent** |
| First paint (FCP) | Slow | Fast | Fast |
| Interactive (TTI) | Slow | After hydration | After hydration |
| SEO | Riskiest | Strong | Strong |
| Data freshness | Live | Live | As of last build |
| Cost | Low server | Server per request | Cheapest (static) |
| Best for | Dashboards, apps | Personalized, fresh | Content, docs, marketing |

## The metrics, honestly

The trade-offs no comparison states cleanly. **SSG** wins time-to-first-byte outright and consistently — a CDN hands back a prebuilt file. **SSR** *raises* TTFB (the server must render before it can respond) but still beats CSR on first paint, and it ships fresh data. **CSR** has a fast TTFB (the shell is tiny) but a slow first paint and slow time-to-interactive, because nothing is visible until the bundle runs. And the one everyone glosses: **SSR and SSG don't fix TTI.** Both send HTML that *looks* ready, then **hydration** — downloading, parsing, and executing the JavaScript to attach interactivity — runs anyway. That's the "looks ready but isn't clickable" gap, and it's why the shipped-JS bill is the real interactivity tax, motivating islands, partial hydration, and server components that ship less of it.

## The 2026 spectrum: ISR, streaming, RSC

The trio is a teaching simplification; production is a spectrum. **ISR (incremental static regeneration)** serves static pages but regenerates them on an interval or on demand — SSG speed with periodic freshness, at the price of occasional staleness. **Streaming SSR** sends HTML in chunks as it's generated, so the shell paints in tens of milliseconds while slow content streams behind it. **Server components** run only on the server, ship *zero* JavaScript for non-interactive parts, and can read data directly — the newest answer to hydration cost. None of these change the backend contract; they're finer control over *when the HTML forms and how much JS follows it*, which is the same axis this whole entry turns on.

## It's per-route, not per-app

The mental upgrade that dissolves most "which one?" debates: **you don't pick one strategy for the whole site.** A single app routinely mixes them — a statically generated marketing homepage, an ISR-regenerated product catalog, a server-rendered personalized dashboard, and client-rendered interactive widgets — each route choosing by its own needs. The question is never "SSR or CSR or SSG for my app?" but "which for *this page*?", and the answer follows the page's data: same-for-everyone and stable → static; personalized or fresh → server; behind a login and highly interactive → client.

## Which strategy per page? A decision matrix

| Page type | Rendering |
| --- | --- |
| Marketing, landing, blog, docs | SSG |
| Product catalog, news, feeds | ISR (static + periodic refresh) |
| Personalized, auth-gated, cart, search | SSR (or streaming) |
| Dashboards, internal tools | CSR |
| Real-time, highly interactive | CSR + [live data](/glossary/real-time-live-queries/) |
| SEO-critical content | Not CSR — server-render or prebuild |

## Common use cases

- **Content sites** — SSG plus a [CDN](/glossary/cdn-content-delivery-network/) for instant, crawler-friendly pages (the [JAMstack](/glossary/jamstack/) pattern).
- **E-commerce** — ISR catalog pages, SSR cart and checkout, CSR interactive filters — three strategies, one store.
- **SaaS dashboards** — CSR behind a login, where SEO doesn't matter and interactivity does.
- **News and publishing** — SSR or ISR for freshness with SEO.
- **[PWAs](/glossary/progressive-web-app-pwa/)** — a rendered shell plus client-side interactivity and offline caching.

## Limitations and trade-offs

- **CSR's SEO risk is real but overstated.** Crawlers render JavaScript with a budget; CSR is fine off the indexable path and a gamble on it — nuance, not absolutism.
- **SSR costs server compute.** Rendering every request has a price in TTFB and infrastructure that a CDN-served static file doesn't.
- **SSG's freshness lag.** Build-time data is stale until the next build; large or fast-changing sites need ISR or long builds.
- **Hydration is the hidden tax.** Server-rendered HTML still ships JS to become interactive; first paint fast, first *click* not necessarily.
- **Mixing adds cognitive load.** Per-route rendering is powerful and means reasoning about several data-fetch timings in one app — the flexibility has a complexity cost.

## Rendering on Back4app

Back4app is an open-source Backend-as-a-Service (BaaS) platform that combines a managed database, auto-generated REST and GraphQL APIs, authentication, file storage, and Cloud Code serverless functions. It is the constant beneath the rendering choice: the [REST and GraphQL APIs](/glossary/auto-generated-database-apis/) feed **SSG at build time**, **SSR per request on the server**, and **CSR from the browser** — the identical endpoint the code tabs show, consumed at three different moments — so switching a route's strategy never touches the backend. The reframe this article opens with becomes a working convenience: because rendering is a frontend decision and the data lives behind one stable API with its own [auth](/glossary/authentication-vs-authorization/) and [permissions](/glossary/access-control-lists-acl/), a team can prebuild the blog, server-render the dashboard, and client-render the app shell against the same Back4app backend — picking per page, changing nothing underneath.
