ESC

Type to search the knowledge base.

SSR CSR Islands Architecture

System design for SSR, CSR, and islands — pick rendering per surface, hydrate less, and stream wisely.

intermediate4 min read
  • system-design
  • interview
  • architecture
  • ssr
  • islands

Scope the problem

Choose where HTML is produced and how much JS hydrates. Senior answers assign rendering modes per surface instead of one slogan for the whole company.

Rendering modes

Mode HTML Interactivity Best for
CSR minimal shell full client render authenticated apps, dashboards
SSR per request hydrate personalized SEO pages
SSG build time hydrate/partial docs, marketing
ISR SSG + revalidate hydrate catalogs
Islands static HTML hydrate islands only content sites with widgets
Streaming SSR chunked HTML progressive slow data parts

Mental model

Request
  → resolve data
  → render HTML (server or edge or build)
  → ship minimal JS
  → hydrate only interactive islands
  → client navigations may CSR thereafter

Islands architecture

Page is mostly static HTML/CSS. Interactive spots are islands:

[ static article body ]
[ island: comments ]
[ island: likes button ]
[ island: search box ]

Each island loads its own JS when needed (eager, visible, idle).

<!-- conceptual -->
<article>...</article>
<div data-island="comments" data-props='{"id":"1"}'></div>
<script type="module" src="/islands/comments.js"></script>

Frameworks: Astro islands, Fresh, partial hydration ideas in React (selective hydrate).

Benefits

  • Less main-thread JS → better INP/TBT
  • Content readable without JS
  • Independent island versioning possible

Costs

  • Cross-island state harder
  • Duplicate framework runtimes if careless
  • Routing model different from SPA

SSR + hydration pitfalls

  1. Hydration mismatch — server HTML ≠ client first render (Date.now(), random, locale)
  2. Over-hydration — shipping SPA to show a blog post
  3. Waterfalls — SSR waits on all data before byte 1 (use streaming)
// bad: pure client-only check during SSR
const width = window.innerWidth;

Use useEffect for browser-only values or render consistent placeholders.

Streaming SSR

Shell (nav, layout) flushes early
  → Suspense boundary waits product data
  → streams product HTML
  → deferred secondary widgets

Improves TTFB perception; coordinate with SEO (ensure critical content included).

Hybrid product map (example e-commerce)

Surface Mode
Home marketing SSG/ISR + islands (promo carousel)
PDP SSR/ISR for SEO + client ATC island
Cart/checkout CSR SPA (auth, dynamic)
Help docs SSG
Admin CSR

Data fetching placement

Place Use
Build stable content
Server request user-specific, SEO
Client highly interactive, private

Avoid double-fetch: serialize server state into HTML (__DATA__) for hydration reuse.

Performance comparison levers

  • CSR: great after load; weak first contentful for content sites
  • SSR: better first paint of data; server cost
  • Islands: minimize JS
  • Edge SSR: latency (edge tradeoffs)

Caching interactions

Static/ISR HTML caches well. SSR personalized HTML often private. Islands that fetch client-side can keep HTML cacheable — powerful combo.

Tradeoffs

  1. SPA DX (shared state, client routing) vs multi-page islands
  2. Full React SSR vs lighter HTML-first frameworks
  3. Streaming complexity vs slower complete HTML
  4. SEO needs force SSR/SSG even if CSR feels easier

Interview close

Map surfaces → pick mode per surface → default to ship less JS via islands/static → SSR only when needed → stream slow parts → avoid hydration mismatches. End with caching implications.

Decision flowchart (say out loud)

Is SEO / first content critical?
  yes → SSG/ISR/SSR
  no  → CSR OK
Is most of the page static?
  yes → islands / partial hydration
  no  → full app hydration maybe fine
Is data personalized + cacheable shell?
  → static shell + client islands for user bits

Migration path from SPA

  1. Extract marketing routes to SSG
  2. SSR product pages
  3. Leave app dashboard CSR
  4. Introduce islands for heavy widgets on content pages

Don’t rewrite the world in one quarter—render modes can coexist behind one design system.

Hydration cost metric

Track JS KB to interactive and long tasks during hydration. If hydration long-tasks dominate INP, you over-hydrated—split islands or defer non-visible widgets.

Further reading