A site built with a modern JavaScript framework can be generated on the server and reach the browser as complete HTML: text, images and structure are visible early, and LCP is often good. Yet in many cases, for a few seconds the page does not respond to clicks, menus do not open and fields do not react. The culprit has a precise name: hydration.
What hydration is
In classic server-side rendering of a component-based application, the server runs the components and produces HTML. That HTML is "dry", though: it has no event handlers and no state. To make it interactive, the browser must:
- download the JavaScript for every component on the page;
- run them again, rebuilding in memory the same structure already present in the HTML;
- attach event handlers to the existing elements.
That process is hydration. Its weak point is that it works on the entire page, including the parts with nothing interactive about them: the text of an article, the footer, a static list. The JavaScript for those components is sent and executed anyway, only to discover that there is nothing to attach.
The result is a gap between when the page looks ready and when it is ready. Time spent hydrating shows up as long tasks on the main thread, which worsen the INP of the first interactions.
How much of the page is really interactive
A useful exercise is to look at a typical page and mark the parts that need JavaScript. On a product page, for example:
| Part of the page | Interactive? |
|---|---|
| Header with logo and links | No, except the mobile menu |
| Image gallery | Yes |
| Title, price, description | No |
| Size picker and cart button | Yes |
| Reviews | No, except the "Show more" button |
| Footer | No |
The interactive part is often a minority. Hydrating everything means paying, for the entire page, a price that only some areas need.
The alternatives
In recent years several approaches have emerged to reduce this work. They are not mutually exclusive and the names vary across frameworks.
Progressive or deferred hydration
Components are hydrated at different times rather than all at once: the visible ones immediately, the others when they scroll into view, when the browser is idle or on the user's first contact. Total JavaScript does not change, but it is spread over time and does not block the first interactions.
Islands architecture
The page is treated as static HTML by default, and only some explicitly declared areas, the islands, receive JavaScript and are hydrated independently. Astro popularized this model: a component becomes interactive only if you mark it as such, and you can choose when to hydrate it.
<Header />
<Gallery client:visible />
<ProductDescription />
<SizePicker client:load />
<Reviews />
In this example only the gallery and the size picker send JavaScript to the browser; the rest arrives as plain HTML.
Server components
Some frameworks, such as React with Server Components, distinguish between components that run only on the server, whose code is never sent to the browser, and client components that are hydrated. The principle is similar to islands, but integrated into an application's component tree.
Resumability instead of hydration
A more radical approach, adopted for example by Qwik, avoids re-running components in the browser: the server serializes the necessary state into the HTML, and the code for a handler is downloaded only when the corresponding event occurs. The initial work in the browser becomes minimal.
How to choose
The choice depends on the nature of the site more than on trends:
- content sites (blogs, documentation, corporate sites, catalogues): islands architecture or static generation with a little targeted JavaScript is almost always the best choice;
- highly interactive applications (editors, dashboards, tools): full hydration makes more sense, because much of the page really is interactive, but splitting code by route is still worthwhile;
- mixed sites (e-commerce, portals): server components or islands let you keep content parts static and make only the necessary ones interactive.
In my work, migrating a content site from a fully hydrated application to an islands model has often cut initial JavaScript drastically without changing anything visible to the user.
How to measure the current cost
To understand how much hydration weighs on an existing site:
- record a load in the DevTools Performance panel with CPU throttling and look for long tasks right after the first paint: they often carry the names of the framework's hydration functions;
- compare the moment of LCP with the moment the main thread becomes free;
- check in the Coverage panel how much of the downloaded JavaScript runs only to build non-interactive components;
- see in field data whether the INP of first interactions is worse than that of later ones.
In short
- Hydration re-runs server-rendered components in the browser to make them interactive.
- Hydrating the whole page wastes work on static parts and delays the first interactions.
- Deferred hydration, islands, server components and resumability reduce or spread that work.
- Content sites benefit most from islands and minimal JavaScript.
- Measure with the Performance panel and with the INP of first interactions.