# Quick start

> Install hydration-proof, run it against your Next.js, Remix or Astro app, and read the report: every React hydration mismatch, its cause and the fix.

Source: https://hydration.jscrate.dev/docs/quick-start
Last updated: 2026-09-18

hydration-proof finds React hydration errors by loading every route of your
server-rendered app in a real browser and comparing the server HTML with what
React renders on the client. Install it, run `npx hydration-proof test`, and it
tells you which element differs, both values, the likely cause and the fix.

## Install hydration-proof

Add it as a dev dependency, then download the browser once:

```bash
npm install -D hydration-proof
npx hydration-proof install   # downloads Chromium
```

It needs Node.js 22.18 or newer, and works with npm, pnpm, Yarn (including
Plug'n'Play) and Bun. There are no install scripts: browsers are only
downloaded by the `install` command, into Playwright's shared cache, so a
project that already uses the same Playwright version does not download them
again.

To catch the same mistakes in your editor, add the
[ESLint plugin](https://hydration.jscrate.dev/docs/eslint) as well:

```bash
npm install -D eslint-plugin-hydration-proof
```

## Run your first test

```bash
npx hydration-proof init   # creates hydration-proof.config.ts
npx hydration-proof test
```

For Next.js, React Router, Remix and Astro apps that is all. hydration-proof:

1. discovers your routes from `app/`, `pages/` and the build output,
2. builds the app if there is no build yet, and starts it on a free port,
3. loads every route and compares the server HTML with the hydrated DOM,
4. exits with code `1` if it found a problem.

Vite SSR and custom Node servers are detected too. Any other setup works with
`--url` (see [adapters](https://hydration.jscrate.dev/docs/adapters)).

## Read the report

Each finding in the terminal shows the issue code, the element, the value on
each side, the source line and a fix:

```text
Hydration Proof — 20 pages on http://localhost:3000

  ✓ /pricing 684ms
  ✖ /dashboard 1.1s  1 error
    HP1001 Text differs between server and client  (timezone difference, 95%)
      #last-login  in LastLogin
      server: "Signed in at 5:00 AM"
      client: "Signed in at 10:00 AM"
      app/dashboard/LastLogin.tsx:14:10
      → Pass an explicit timeZone to the formatter (the same on both sides), or format the date after mount.

  Report: .hydration-proof/report/report.html
```

- `HP1001` is a stable [issue code](https://hydration.jscrate.dev/docs/issues/hp1001) with its own page.
- `timezone difference, 95%` is the [likely cause](https://hydration.jscrate.dev/docs/causes/timezone) and
  how sure hydration-proof is.

Open `.hydration-proof/report/report.html` for everything at once: filters,
the server and client values side by side, the code, screenshots with the
element outlined, and a timeline of the page. [Reports](https://hydration.jscrate.dev/docs/reports) covers
every output format.

## Test an app that is already running

```bash
npx hydration-proof test --url http://localhost:3000 --route / --route /pricing
```

With `--url`, nothing is built or started, and only the routes you name are
tested. Add `--sitemap` to test the pages in your sitemap, or `--crawl` to
follow links from the tested pages.

## Test development and production builds

Development builds give exact source lines. Production builds show what your
users get, including attribute mismatches React 19 never reports in
production. Test both in one run:

```bash
npx hydration-proof test --mode both
```

## Add it to CI

```yaml title=".github/workflows/hydration.yml"
- run: npm ci
- run: npx hydration-proof install --with-deps
- run: npx hydration-proof test
```

Or let `npx hydration-proof init --ci github` write the workflow for you.
[Detect hydration errors in CI](https://hydration.jscrate.dev/docs/ci) covers GitHub Actions, GitLab and
CircleCI, sharding, baselines and budgets.

## Configure it

The config file is optional for most apps. When you need it, it is TypeScript
with completion:

```ts title="hydration-proof.config.ts"
import { defineConfig } from "hydration-proof";

export default defineConfig({
  routes: {
    // Example values for dynamic routes
    dynamic: { "/products/[id]": ["1", "42"] },
    exclude: ["/api/**"],
  },
  // The environments your users have
  scenarios: [
    { name: "default" },
    { name: "dark-mobile", colorScheme: "dark", viewport: "mobile" },
    { name: "karachi", locale: "ur-PK", timezoneId: "Asia/Karachi" },
  ],
});
```

See [configuration](https://hydration.jscrate.dev/docs/configuration) for every option, and
[scenarios](https://hydration.jscrate.dev/docs/scenarios) for signed-in pages.

## Related

- [How hydration-proof works](https://hydration.jscrate.dev/docs/how-it-works): the six snapshots it
  compares
- [What is hydration in React?](https://hydration.jscrate.dev/docs/guides/what-is-hydration)
- [All React hydration error messages](https://hydration.jscrate.dev/docs/errors), decoded
- [Common causes of hydration errors](https://hydration.jscrate.dev/docs/causes) and their fixes
- [The CLI](https://hydration.jscrate.dev/docs/cli): every command and flag
