Web Architecture Generations

SSR, CSR, Hybrid — who builds the HTML the user sees?

Server-Side Rendering (SSR)

The biggest architectural decision in web development: who builds the HTML that the user sees?

The server generates complete HTML for every request. The browser receives a finished page and just displays it.

Client                              Server
  │                                    │
  │──── GET /products ────────────────>│
  │                                    │  Server queries DB,
  │                                    │  builds HTML with data,
  │                                    │  sends complete page
  │<──── <html><body>...products...    │
  │                                    │
  │  Browser displays HTML immediately │
  │  No JavaScript needed to see content

Client-Side Rendering (CSR)

The server sends a minimal HTML shell plus a large JavaScript bundle. The JavaScript fetches data via API and builds the page in the browser.

Client                              Server
  │                                    │
  │──── GET /products ────────────────>│
  │<──── <html><div id="root"></div>   │  Nearly empty HTML
  │      + app.js (2MB)                │
  │                                    │
  │  JS loads, initializes framework   │
  │                                    │
  │──── GET /api/products ────────────>│
  │<──── {"products": [...]}           │  JSON data
  │                                    │
  │  JS builds DOM, renders page       │
  │  User finally sees content         │

Comparing the Approaches

Aspect SSR CSR Hybrid
First page load Fast (HTML ready) Slow (JS must load + execute + fetch) Fast (HTML ready, JS enhances)
Subsequent navigation Slow (full page reload) Fast (client-side routing) Can be fast (progressive loading)
SEO Excellent Poor (without SSR pre-rendering) Excellent
Works without JS Yes No Yes (degraded gracefully)
Server load Higher (renders every page) Lower (serves static files + API) Moderate
Complexity Low High (state management, routing, build) Very High

The Generational Evolution

Web architecture hasn't evolved in a straight line — it has moved through distinct generations, each solving the problems of the previous one while creating new trade-offs. Critically, all generations remain legitimate. The right choice depends on the problem, not the calendar.

Generation Era Approach Characteristics
Gen 1: Server-Side Focused ~1993–1999 Thin client, server renders everything 1 URL = 1 page. Simple, but every interaction required a full page reload.
Gen 1.5: Enhanced Client ~1997–2004 Server-side + progressive enhancement Client-side form validation, DHTML effects. Server still controls flow.
Gen 2: Ajax ~2005–2012 XMLHttpRequest, in-place updates Broke 1 URL = 1 resource (hashbang URLs, then History API fixed it). Gmail, Google Maps as pioneers.
Gen 3: Native Apps ~2008–present iOS/Android, app store distribution Web views as hybrid compromise. Native performance, but platform lock-in and distribution friction.
Gen 4: PWAs ~2015–present Offline-first, service workers Speed of native + web distribution. Install without app stores. Still maturing.
Current: SSR + Hydration ~2018–present Send static snapshot fast, then hydrate with JS Best of SSR and CSR. Frameworks like Next.js, Nuxt, Astro. Complexity is the cost.

Form Follows Function

The appropriate architectural approach reveals itself from the problem, not from trends. The decision process:

  1. Is this a site or an app? (Tutorial 13) — Content-dominant or interaction-dominant?
  2. What degree of dynamism does it need? — Static content? Real-time data? User-generated content?
  3. What's the context? — Audience, constraints, team capabilities, business requirements.

To believe that only the latest generation is valid is to be too wrapped up with form and not function. A static HTML site is the right answer for many problems. A full SPA with SSR and hydration is the right answer for others. The wrong choice in either direction — over-engineering a brochure site or under-engineering a complex app — creates unnecessary pain.

Maturity-Safety Matrix

When evaluating technologies, consider two axes:

  • Maturity: How long has it been used in production? How stable is the API? How large is the community?
  • Safety: What's the blast radius if it fails? How well understood are the security implications?

Mature, safe technologies (HTML, CSS, server-rendered pages) are boring but reliable. Immature, risky technologies (the latest JS framework) are exciting but may not survive. For production systems, especially those meant to be long-lived, a boring, mature, and stable solution is critical.