FSD Frontend System Design

Part III β€” The Speed Β· Lesson 5.6

Rendering Patterns

In one lineWhere and when HTML gets built β€” CSR, SSR, SSG, ISR, streaming β€” decides your LCP before you write a line.

Where you've seen itAn e-commerce product page: static description, live price, and reviews that appear a moment later. Three patterns, one screen.

  • Time18 min
  • DiagramSix patterns on the same timeline
  • Chapter5 Β· Performance

Diagram

diagram
THE SAME PAGE, SIX WAYS  (β–“ blank Β· β–‘ visible Β· β–ˆ interactive)

  CSR       β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ     download JS β†’ fetch β†’ render
            slow LCP, simple infra, great for dashboards behind login

  SSR       β–“β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–“β–ˆβ–ˆβ–ˆβ–ˆ      HTML per request, then hydrate
            fast LCP, personalised, costs server time per view

  SSG       β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“β–ˆβ–ˆβ–ˆβ–ˆ      HTML at build time, from CDN
            fastest LCP, stale until rebuilt

  ISR       β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“β–ˆβ–ˆβ–ˆβ–ˆ      SSG + background revalidation
            fast AND fresh, cache complexity

  STREAM    β–“β–‘β–‘β–‘β–’β–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ      shell now, slow parts stream in
            fastest useful paint, needs streaming-capable infra

  ISLANDS   β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–‘β–‘β–ˆ      static HTML + tiny interactive bits
            least JS shipped, not every UI fits
  β”œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€
  0   0.5  1.0  1.5  2.0  2.5  3.0s
diagram
HYDRATION β€” the cost people forget

  server HTML  β–‘β–‘β–‘β–‘  page LOOKS ready at 0.8s
                        β”‚
                        β”‚ ← taps do nothing
                        β–Ό
  JS downloads + hydrates β–ˆβ–ˆβ–ˆβ–ˆ  actually ready at 2.4s

  This 1.6s gap is where "it looked loaded but froze" comes from.
  Streaming + selective hydration + islands all attack this gap.
diagram
CHOOSING β€” by content freshness and personalisation

                    β”‚ same for everyone β”‚ per-user
  ──────────────────┼───────────────────┼──────────────────
  changes rarely    β”‚  SSG / ISR        β”‚  SSG shell +
  (docs, marketing) β”‚                   β”‚  client fetch
  ──────────────────┼───────────────────┼──────────────────
  changes often     β”‚  ISR / SSR +      β”‚  SSR / streaming
  (feed, prices)    β”‚  edge cache       β”‚
  ──────────────────┼───────────────────┼──────────────────
  behind login      β”‚       β€”           β”‚  CSR is fine
  (dashboards)      β”‚                   β”‚

How it works

  1. SSG/ISR for anything cacheable β€” the CDN answers in ~30ms and no server runs per view.
  2. SSR when the HTML must differ per user and SEO or LCP matters.
  3. Stream so the shell paints immediately while slow data (reviews, recommendations) arrives in later chunks.
  4. CSR is perfectly correct behind a login where SEO is irrelevant and the app is long-lived.
  5. Mix per route, and per component. The interview answer is almost never one pattern for a whole app.

Trade-offs

PatternLCPFreshnessServer cost
CSRworstlivenone
SSRgoodliveper request
SSGbestbuild-timenone
ISRbestnear-liveoccasional
Streamingbest usefulliveper request
Islandsbestdependslow

Interview angle

"SSR or CSR for an e-commerce site?"

  • Per route: product and category pages need SEO and fast LCP β†’ SSG/ISR at the edge; cart and account are CSR behind login.
  • Price and stock are the genuinely dynamic bits β€” fetch those client-side or stream them into a static shell.
  • Name hydration cost explicitly: SSR that ships a huge bundle can feel slower than CSR despite a better LCP.

Recap

  • The pattern is chosen per route, by freshness and personalisation.
  • Hydration is the hidden cost β€” looking ready isn't being ready.
  • Static shell + streamed dynamic parts is the default answer for most content sites.