# Hydration

> Attach the browser runtime to server-rendered markup, and verify the markup matches before it does.

Source: [https://askrjs.com/docs/rendering/hydration](https://askrjs.com/docs/rendering/hydration)

Status: stable. Packages: @askrjs/askr.

**Published packages are authoritative.** Examples may lag behind a published contract. When guidance differs, verify the exports and TypeScript declarations in your installed package, then file an issue.

## Example

Keep the route tree shared and change the delivery adapter—not the component contract—when moving between client, server, and static rendering.

```tsx
import { createSPA, hydrateSPA } from '@askrjs/askr/boot';

const root = document.getElementById('app')!;
if (root.childNodes.length) {
  await hydrateSPA({ root, registry });
} else {
  await createSPA({ root, registry });
}
```

## Adopt server markup

`hydrateSPA` (from `@askrjs/askr/boot`) attaches the client runtime to HTML that a server already rendered, given the same `root` and explicit `registry` used by the server, plus an optional `dataRuntime` for reusing server-fetched data on the client. It's the counterpart to `createSPA`: `createSPA` builds the DOM from scratch, `hydrateSPA` claims DOM that's already there.

## Deterministic first render

SSR and hydration share a numeric `seed` (see `createRenderContext(seed, ...)` and `renderToStringSync`'s `seed` option) so that keys and internal ordering generated during server render can be reproduced exactly on the client. Without matching seeds, the client's first pass could generate different keys than the server did, and hydration would treat identical markup as mismatched.

## Event attachment

Hydration walks the existing DOM tree and attaches event listeners to the elements the component tree expects, rather than replacing nodes outright. `hydrate.deferUntilIdle` and `hydrate.deferBelowFold` (with `foldThreshold`) on `HydrateSPAConfig` let you push that listener attachment to idle time or until an element scrolls into view, trading immediate interactivity for less main-thread work at load.

## Mismatch diagnostics

Set `hydrate: { verifyMarkup: true }` on `hydrateSPA` to have it check server-rendered markup against what the client would produce before attaching to it, surfacing a mismatch instead of silently adopting the wrong structure. `hydrate.skipSelectors` excludes known-divergent regions (third-party widgets, ads) from event-listener attachment and deferred-boundary tracking — it does not exempt those regions from the markup-verification check itself, so a third-party widget that mutates its own markup can still trigger a mismatch there even while listed in `skipSelectors`.

## Documentation navigation

[Previous](https://askrjs.com/docs/rendering/streaming/index.md) | [Next](https://askrjs.com/docs/rendering/selective-hydration/index.md)
