Skip to content
Now accepting new projects — limited slots available. Get started →
Frameworks · Updated Aug 2, 2026

What is Hydration?

Hydration is a framework process that attaches JavaScript interactivity to server-rendered HTML in the browser.

What is Hydration?

Hydration is when your JavaScript framework takes static HTML from the server and "wakes it up" in the browser—attaching event listeners, restoring state, reconciling the virtual DOM with what's already rendered. React popularized the term around 2016 with ReactDOM.hydrate() (now hydrateRoot() since React 18, released March 2022).

The framework re-executes your component logic client-side, walks the existing DOM tree, and binds interactivity without rebuilding nodes from scratch. This is different from client-side rendering, where the browser gets an empty <div> and builds everything from JavaScript.

The main trade-off? The "uncanny valley"—the page looks ready before it actually responds to clicks. On a typical e-commerce product page, hydration can block the main thread for 200–800ms depending on component count. That hits Interaction to Next Paint (INP) hard. We've shipped hydration-aware architectures on 50+ projects. Step one is always measuring Time to Interactive before and after.

How it works

When a user requests a page from a server-rendered app (Next.js, Nuxt, SvelteKit), the server runs your component code, produces an HTML string, and sends it with a JavaScript bundle. Here's what happens next:

  1. Browser paints HTML. User sees content immediately—this is the First Contentful Paint (FCP) benefit of SSR.
  2. JavaScript downloads and parses. The framework bundle loads. On slow 3G, this can take seconds.
  3. Hydration begins. Framework walks the DOM tree, matches it against the component tree it would've generated, attaches event handlers, initializes state.
  4. Page becomes interactive. Only now do buttons, forms, and dynamic elements actually work.

React 18+ lets you hydrate selectively:

import { Suspense } from 'react';
import { hydrateRoot } from 'react-dom/client';

hydrateRoot(
  document.getElementById('root'),
  <App>
    <Suspense fallback={<Spinner />}>
      <HeavyDashboard />
    </Suspense>
  </App>
);

With Suspense, React can hydrate parts of the page independently, prioritizing what the user interacts with first. Next.js App Router (13.4+) uses this by default with React Server Components, reducing the total JavaScript that needs hydrating by keeping server-only components out of the client bundle entirely.

The key cost: hydration re-executes your component tree. Every useState initializer, every derived calculation, every context provider—all run again. That's redundant work. It's the core problem newer approaches like resumability (Qwik) and partial hydration (Astro) aim to solve.

When to use it

Traditional full hydration is still the default for most SSR frameworks. Here's when it makes sense—and when it doesn't.

Use full hydration when:

  • Your page is highly interactive (dashboards, editors, real-time apps) and most components need JavaScript anyway
  • You're on React/Next.js or Vue/Nuxt and your bundle is well-optimized (code-split, tree-shaken)
  • You need full client-side routing after the initial load (SPA-like transitions)

Consider alternatives when:

  • Your page is mostly content with isolated interactive widgets—use Astro's island architecture or partial hydration
  • You're optimizing for INP on pages with 100+ components—selective hydration or React Server Components can cut main-thread work significantly
  • Your audience is on low-end devices—Qwik's resumability approach skips hydration entirely by serializing event bindings into HTML

Our preferred stack for content-heavy sites is Astro with islands, specifically because it avoids hydrating content that doesn't need it. For app-like experiences, we stick with Next.js App Router and lean heavily on Server Components.

Hydration vs alternatives

Approach Framework JS Shipped Interactivity Delay Trade-off
Full Hydration Next.js (Pages Router), Nuxt 3 Entire component tree Medium-High Re-executes all components
Selective Hydration Next.js (App Router), React 18+ Reduced via Server Components Medium Still hydrates interactive subtrees
Partial Hydration (Islands) Astro, Eleventy + islands Only island components Low No client-side routing by default
Resumability Qwik Near-zero upfront Very Low Newer ecosystem, smaller community
Client-Side Rendering Vite + React SPA Everything High (no SSR benefit) No HTML until JS runs

Full hydration is the most understood and best-supported pattern. Alternatives require architectural buy-in—you can't bolt islands onto an existing Next.js Pages Router app without a rewrite.

Real-world example

We migrated a media publisher from Next.js 14 Pages Router (full hydration) to App Router with React Server Components. Article pages had ~90 components in the tree, but only 12 were interactive (comment box, share buttons, ad slots).

After migration, we wrapped only those 12 in 'use client' boundaries. Hydration JavaScript dropped from 187 KB to 64 KB (gzipped). Lighthouse Time to Interactive improved by 1.4 seconds on a simulated Moto G Power throttle profile. INP on real Chrome UX Report data went from 380ms (poor) to 160ms (good) over 28 days.

The takeaway: if you're hydrating components that never needed JavaScript, you're paying a tax on every page load.

Frequently asked questions about Hydration

Is hydration the same as client-side rendering?
No. Client-side rendering (CSR) means the server sends a mostly empty HTML document and JavaScript builds the entire DOM from scratch in the browser. Hydration assumes the HTML already exists — it was rendered on the server. The framework's job during hydration is to attach event listeners and state to that existing markup without destroying and recreating DOM nodes. The user experience difference is significant: with CSR, the user sees a blank page until JavaScript loads and executes. With SSR + hydration, the user sees content immediately but can't interact until hydration completes. Both have a delay before full interactivity, but hydration gives a much faster FCP.
When did hydration become standard in web frameworks?
The concept existed in earlier frameworks, but React formalized it with `ReactDOM.hydrate()` around React 16 in September 2017. Before that, `ReactDOM.render()` on server-rendered markup would work but was less efficient. Vue introduced SSR hydration in Vue 2.x around the same time, and Nuxt 1.0 (released January 2018) made it the default. By 2020, hydration was the standard approach for any framework offering SSR. React 18 (March 2022) introduced selective hydration with `hydrateRoot()` and Suspense boundaries, which was the biggest evolution of the concept since its introduction.
What's the alternative to hydration?
The main alternatives are partial hydration, island architecture, and resumability. Partial hydration (used by Astro since its 1.0 release in August 2022) only hydrates explicitly marked interactive components, leaving everything else as static HTML. Island architecture is the pattern behind this — each interactive widget is an "island" in a sea of static content. Resumability, pioneered by Qwik (1.0 in May 2023), takes a different approach entirely: it serializes event handler references directly into the HTML, so the framework can respond to user interactions without replaying the component tree at all. Each approach trades ecosystem maturity for performance gains.
Does hydration affect Core Web Vitals?
Yes, directly. Hydration runs JavaScript on the main thread, which blocks user interaction. This impacts Interaction to Next Paint (INP), which replaced First Input Delay as a Core Web Vital in March 2024. A heavy hydration pass can easily push INP above the 200ms "good" threshold. It can also affect Total Blocking Time (TBT) in Lighthouse, since hydration often produces long tasks (>50ms). It doesn't typically hurt Largest Contentful Paint (LCP) since the HTML is already rendered, but if hydration triggers layout shifts — say, a component re-renders with different dimensions — it can worsen Cumulative Layout Shift (CLS) too.
Get in touch

Let's build
something together.

Whether it's a migration, a new build, or an SEO challenge — the Social Animal team would love to hear from you.

Get in touch →