What is Partial Hydration?
Partial hydration is a rendering strategy that selectively adds JavaScript interactivity to specific components on an otherwise static page.
What is Partial Hydration?
Partial hydration is a rendering strategy where only specific interactive components on a server-rendered page receive client-side JavaScript, while the rest of the page stays as static HTML. Unlike full hydration — where the entire component tree is re-initialized in the browser — partial hydration identifies which pieces of UI actually need interactivity and ships JavaScript only for those. The concept gained real traction in 2021-2022 with frameworks like Astro (which hit 1.0 in August 2022) and Marko. In practice, a page with a static hero, article body, and one interactive carousel would only hydrate the carousel. This dramatically reduces the amount of JavaScript sent to the client. On content-heavy sites we've shipped, partial hydration regularly cuts Total Blocking Time by 40-60% compared to full-hydration SPAs, which directly improves Core Web Vitals like INP and LCP.
How it works
In a full hydration model (think traditional Next.js or Nuxt), the server renders HTML, then the browser downloads the full JavaScript bundle and replays the component tree to attach event listeners and state. Every component hydrates, even if it's purely presentational.
Partial hydration flips this. The framework needs a way to mark which components are interactive. Astro uses client:* directives:
---
import StaticHero from '../components/Hero.astro';
import InteractiveCarousel from '../components/Carousel.tsx';
---
<StaticHero />
<!-- No JS shipped for this component -->
<InteractiveCarousel client:visible />
<!-- Hydrated only when scrolled into viewport -->
The client:visible directive tells Astro to lazy-hydrate the carousel using an IntersectionObserver. Other directives include client:load (hydrate immediately), client:idle (hydrate on requestIdleCallback), and client:media (hydrate on media query match).
Under the hood, the build step splits JavaScript so that only the code for marked components is bundled into separate, smaller chunks. Static components compile to zero client-side JS. The server sends fully rendered HTML for everything, so the page is visible and readable before any JavaScript executes. When the hydration trigger fires, the framework loads the component's JS chunk and attaches reactivity to the already-rendered DOM nodes.
This differs from progressive hydration (hydrating the full tree in priority order) because components that aren't marked simply never hydrate at all.
When to use it
Partial hydration shines on content-first sites where most of the page is static and only small sections need interactivity.
Use it when:
- Marketing sites, blogs, docs, and e-commerce product pages where 80%+ of the page is static content
- You're failing Core Web Vitals due to excessive JavaScript (high TBT, poor INP)
- You want to mix UI frameworks — Astro lets you hydrate React, Svelte, Vue, and Solid components on the same page
- SEO matters and you need fast, indexable HTML with minimal JS overhead
Skip it when:
- Your entire UI is interactive (dashboards, complex SPAs, real-time collaboration tools) — you'll end up hydrating everything anyway
- You need persistent client-side state across the page and shared context between many components
- Your team is deeply invested in a full-framework approach (Next.js App Router with RSC already addresses some of the same problems differently)
Partial Hydration vs alternatives
| Strategy | JS shipped to client | When hydration runs | Best for |
|---|---|---|---|
| Full Hydration | Entire component tree | On page load | SPAs, highly interactive apps |
| Partial Hydration | Only interactive components | Per-component trigger | Content sites with some interactivity |
| Progressive Hydration | Entire component tree | Prioritized / lazy | SPAs wanting better TTI |
| React Server Components | Only client components | On load (client boundary) | Next.js App Router apps |
| Resumability (Qwik) | Near-zero upfront, lazy per event | On user interaction | Sites wanting zero-hydration cost |
Partial hydration and React Server Components (RSC) solve overlapping problems but differently. RSC still ships a client-side runtime and hydrates the full client subtree. Partial hydration via Astro's island architecture ships no framework runtime for static parts at all. Qwik's resumability takes things further by eliminating hydration entirely and serializing component state into HTML. We've found Astro's model is the most pragmatic for content-heavy sites as of 2026 — the DX is clear and the performance wins are immediate.
Real-world example
We rebuilt a client's documentation site (300+ pages) from a Gatsby SPA to Astro 4 with partial hydration. The old site shipped 280KB of gzipped JavaScript on every page load, even though 95% of the content was static Markdown. After migrating, static pages shipped 12KB of JS total — only a search widget and a theme toggle were hydrated using client:idle. Lighthouse performance scores went from 62-71 to 95-100 across the board. LCP dropped from 3.2s to 1.1s on mobile (simulated 4G). The build took about a week. The key lesson: don't hydrate what doesn't need to be interactive. It sounds obvious, but most frameworks default to hydrating everything.