🧠 Hydration, Selective Hydration & Progressive Hydration Explained (React vs Vue/Nuxt vs Others)



This content originally appeared on DEV Community and was authored by Vishwark

Hydration is one of the most important concepts in modern frontend frameworks, yet also one of the most misunderstood.

In 2025, frameworks like React 18+, Vue/Nuxt 3, SvelteKit, SolidStart, Qwik, Astro all approach hydration differently β€” some progressively, some selectively, some partially, some never fully.

This post breaks it all down with real examples, SSR + SSG scenarios, and an extended example so the concept stays in your mind forever.

🌊 What Is Hydration?

When a page is SSR or SSG, the browser gets plain HTML:

<div id="app">
  <button>Click me</button>
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
  </ul>
</div>

But HTML alone does nothing β€” no JavaScript, no event listeners.

Hydration is when the framework:

  • Loads JS bundles
  • Recreates the virtual component tree
  • Attaches event listeners
  • Activates reactivity
  • Makes the page interactive

Another way to say it:

SSR/SSG gives HTML.
Hydration gives life.

πŸŸ₯ Old Hydration Model (Pre-React 18 / Classic Vue / SvelteKit)

Traditionally, hydration happened linearly, top-to-bottom:

1. Hydrate App()
2. Hydrate Header()
3. Hydrate Navbar()
4. Hydrate Sections()
5. Hydrate Footer()

Linear hydration has three big problems:

❌ 1. Slow Time-To-Interactive

Because hydration must finish before the user can interact safely.

❌ 2. Big JS bundle runs all at once

Blocks main thread.

❌ 3. Offscreen components hydrate early

Even things not visible yet.

This model works, but it’s outdated for large apps.

🟩 React 18+: Selective Hydration (Smarter, Not Linear)

React 18 replaced β€œhydrate everything in order” with:

Hydrate what’s needed, when it’s needed.
Skip or delay the rest.

React evaluates multiple signals:

React 18 automatically detects:

  • Which components are visible
  • Which components are interactive
  • Which have pending Suspense data
  • Which are above-the-fold
  • Which the user interacts with first
  • Which are heavier or lower priority

Hydration priority:

1⃣ Visible + interactive components
2⃣ User-clicked or user-focused components
3⃣ Above-the-fold content
4⃣ Suspense boundaries that resolved
5⃣ Below-the-fold or non-interactive UI
6⃣ Everything else, when browser is idle

This is selective hydration β€” only hydrate the parts users need immediately.

🟦 How Suspense Affects Hydration

Consider:

<Suspense fallback={<LoadingUser />}>
  <UserProfile />
</Suspense>

React can stream HTML in chunks:

  • Server streams <LoadingUser /> first
  • Later streams <UserProfile /> when data resolves
  • Client hydrates these boundaries independently
  • Hydration can happen in the middle, out of order, or scattered

Suspense creates natural hydration islands.

πŸ”₯ BIG Real-World Example (SSR + Suspense + Complex Layout)

Imagine a dashboard:

+----------------------+
| Navbar               |
+----------------------+
| Sidebar | Chart      |
|         | (Suspense) |
|         |            |
+----------------------+

Server Output (HTML)

  • Navbar rendered immediately
  • Sidebar rendered immediately
  • Chart is slow β†’ Suspense fallback is sent

Client sees:

Navbar (interactive instantly)
Sidebar (interactive instantly)
Chart loading skeleton…

Hydration (React 18):

1⃣ User clicks sidebar β†’ React hydrates sidebar immediately
2⃣ Navbar is visible β†’ hydrate early
3⃣ Chart fallback hydrates next (lightweight)
4⃣ Actual Chart component hydrates only when its data resolves
5⃣ Footer hydrates when browser is idle

This is selective, scattered, priority-driven hydration.

🟨 Is Progressive Hydration Needed in React?

React 18 already does a form of progressive hydration:

βœ” Selective hydration
βœ” Suspense boundary hydration
βœ” Hydrate-on-interaction
βœ” Hydrate-visible-first
βœ” Hydrate background content later
βœ” Hydrate streaming chunks as they arrive

React does not call it β€œprogressive hydration,” but practically, it achieves that behavior.

🟩 SSG + Hydration β€” Does Hydration Still Happen?

Yes.

SSG also needs hydration because:

  • HTML is static
  • But JS must still attach event handlers
  • Framework re-runs components on client
  • Event listeners get connected
  • State becomes reactive

Example:
A static blog page still hydrates β€œLike Button”, comments, interactive parts.

SSG = static HTML + hydration on client.

πŸ”° How Other Frameworks Handle Progressive Hydration

Now let’s compare how different frameworks hydrate:

🟦 Vue 3 (Classic) β€” Linear Hydration

Vue’s default hydration is still linear unless using advanced tooling.

Hydration flow:

1. Hydrate root instance
2. Hydrate children in DOM order
3. Hydrate nested components
4. Finally hydrate leaf nodes

Downsides:

  • Slower interactivity for large pages
  • No Suspense-driven hydration
  • No hydrate-on-interaction by default

But this changes with Nuxt 3…

🟩 Nuxt 3 β€” β€œProgressive, Island-Style” Hydration

Nuxt 3 introduced partial hydration capabilities, similar to islands architecture:

βœ” client:only

Component is only hydrated when needed:

<client-only>
  <FancyChart />
</client-only>

βœ” Async Components + Suspense

Nuxt 3 supports Suspense-like behavior:

<Suspense>
  <UserProfile />
</Suspense>

This allows:

  • above-the-fold hydration first
  • async component hydration later
  • streamed HTML + partial hydration

βœ” Nuxt + Nitro + Island Optimizations

Nuxt aggressively optimizes hydration for:

  • per-component hydration
  • hydration skipping for static parts
  • β€œhybrid island architecture”

While it’s not as automatic as React’s selective hydration,
Nuxt 3 can achieve progressive hydration with explicit patterns.

🟧 SvelteKit β€” Progressive Hydration by Default

SvelteKit hydrates:

  • visible sections first
  • interactive sections first
  • lazy components when needed

Svelte also supports component-level hydration:

  • preload only what’s visible
  • lazy load everything else
  • hydrate only when scrolled into view
  • hydrate on interaction

Very efficient because Svelte compiles away most framework runtime.

🟦 SolidStart β€” Fine-Grained Hydration

Solid uses reactive primitives and compiles away components.
Hydration happens:

  • per DOM node
  • per reactive signal
  • not per component

This makes hydration extremely granular.

SolidStart naturally does progressive + selective hydration.

🟣 Qwik β€” No Hydration (Resumes Instead)

Qwik doesn’t hydrate at all.

It resumes the app from HTML with embedded state.
Event listeners are attached lazily.

Progressive hydration is built-in because Qwik doesn’t hydrate entire trees β€” it loads behavior on demand.

πŸŒ‘ Astro β€” Island Architecture (Hydrate Only What You Ask)

Astro hydrates components only when instructed:

<Counter client:load />
<Chart client:visible />
<Sidebar client:idle />

Modes:

  • client:load
  • client:visible
  • client:idle
  • client:media
  • client:hover

A pure island architecture.
Astro minimizes JS for non-interactive content, best-in-class for performance.

🟩 Summary: How Frameworks Hydrate

Framework Hydration Style Notes
React 18+ Selective, priority-based, Suspense-aware Automatic
Vue 3 classic Linear Simple but slower
Nuxt 3 Partial/Client-only/Islands Supports progressive hydration
SvelteKit Progressive Hydrates visible/interacted UI first
SolidStart Fine-grained Tiny hydration chunks
Qwik No hydration β†’ Resume Most advanced
Astro Islands Hydrate only what you choose

πŸŽ‰ Final Thoughts

In modern SSR/SSG frameworks:

  • Hydration is the cost of interactivity
  • Linear hydration is slow
  • Progressive + selective hydration is the future
  • React 18+ achieves it automatically
  • Nuxt 3, SvelteKit, Qwik, Astro each do it differently
  • Suspense brings async-shaped hydration
  • Streaming SSR improves TTFB dramatically

If you understand hydration deeply,
you understand the foundation of modern web frameworks in 2025.


This content originally appeared on DEV Community and was authored by Vishwark