Skip to content
fearchitect
Rendering & Hydration

Hydration Strategies & Islands

Pay JS cost only for interactive regions, not the whole page.

By Abas TurabliReviewed

Summary

Full hydration re-executes React for every node in the server-rendered tree — wasted work on static content. Selective, progressive, and lazy hydration reduce that cost. Islands architecture takes it further: ship a fully static page, then hydrate each interactive widget in isolation. The result is faster TTI and less main-thread blocking on content-heavy pages.

Jump to the interview angle

Hydration

Hydration is the step after SSR where the browser attaches React's event system to server-rendered HTML. Full hydration does this for the entire tree up-front — wasted work on static content.

Selective hydration (React 18): each <Suspense>-wrapped subtree hydrates independently; React prioritises whichever the user clicks first. Progressive/lazy hydration defers non-critical subtrees until idle or visible via IntersectionObserver + dynamic import(). Islands architecture (Astro, Fresh) goes further: the page is static HTML and only explicitly marked components carry their own JS bundle.

Hydration strategies at a glance

StrategyJS shippedWhen hydratesFramework
Full hydrationWhole treePage loadReact / Vue
Selective hydrationWhole treePer Suspense boundaryReact 18
Islands (client:visible)Per island onlyOn viewport entryAstro / Fresh
RSCZero client JSNever (server only)Next.js App Router

Astro island with client:visible

Zero JS ships by default in Astro. Add a client: directive to opt an island into hydration.

Astro island with client:visibleastro
---
// src/pages/index.astro
import HeroImage from "../components/HeroImage.astro"; // static, zero JS
import CommentSection from "../components/CommentSection"; // React island
---
<html>
  <body>
    <HeroImage />

    <!-- Hydrate only when the section scrolls into view -->
    <CommentSection client:visible />
  </body>
</html>

client:visible uses IntersectionObserver; island JS loads only when it enters the viewport. HeroImage is plain Astro — no JS ships for it.

Static page ships zero JS; each island loads and hydrates only when its trigger fires.

next/dynamic with ssr: false requires a Client Component

In Next.js App Router, dynamic(() => import('./Component'), { ssr: false }) is not allowed in Server Components. Wrap the dynamic call in a file marked "use client" and import that wrapper into your Server Component tree instead.

Interview angle

Frame islands as a cost-accounting decision: every interactive component pays a JS tax; static content should pay nothing. Contrast with RSC — islands ship client JS but hydrate lazily; RSC eliminates the component from the client bundle. Name the mismatch hazard.

Soundbite: "Islands ship JS only for interactive widgets; RSC eliminates the component from the client entirely — pick RSC first, island when you need browser APIs."

Key terms

Hydration
Attaching React's event system to server-rendered HTML so it becomes interactive.
Islands architecture
Static-HTML page with isolated interactive components that each carry their own JS bundle.
client:visible
Astro directive that hydrates an island only when it enters the viewport via IntersectionObserver.
Hydration mismatch
Server HTML differs from client render; React discards SSR work and re-renders from scratch.
Selective hydration
React 18 feature: Suspense subtrees hydrate independently; user interaction prioritises which hydrates first.

Further reading

Search fearchitect

Jump to a topic, mode, or action.