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:loadclient:visibleclient:idleclient:mediaclient: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