Check hydration-proof compatibility before adding it to a project. The table below lists the Node.js, React, framework, browser, and package manager versions tested. Stable APIs follow semver: breaking changes require a major release and a migration path.
The hydration-proof compatibility table
- Node.js: 22.18 or later, on Linux, macOS and Windows. Tests cover Node.js 22.18, 24 and 26.
- React: 18.3 and 19.x, in development and production builds. React 18.0–18.2 are not tested; findings may be less precise there.
- Next.js: 15.5 and 16.x, with App Router or Pages Router, webpack or Turbopack. App Router uses Next.js's bundled React; your installed React version matters for Pages Router.
- React Router: Framework mode with
@react-router/dev; fixtures use version 8.4. - Other frameworks: Remix v2, Astro with React islands, Vite SSR and custom Node.js servers.
- Browsers: Chromium, Firefox and WebKit through Playwright. CPU slowdown and native network throttling work only in Chromium.
- Playwright:
playwright-core1.63 or later. An up-to-date copy from your project is reused. - Package managers: npm, pnpm, Yarn Classic, Yarn Berry (including Plug'n'Play) and Bun.
- ESLint plugin: ESLint 9 and 10 with flat config.
Each package manager is tested by installing the packed tarball into a fresh app and running the CLI against it. A version leaving this table is a major release; adding one is not.
Adapters explains how each framework is built, started and read.
How the table is checked
Two workflows in the repository back the table with evidence:
compat.ymlruns the whole fixture suite again against other Next.js versions (16.3, 16.2 and 15.5), and against React 18.3 and 19.0 to 19.3 for the Pages Router and custom SSR.real-world.ymlruns the packed CLI against pinned open-source Next.js apps that nobody on the project wrote: Next.js's ownblog-starter,with-styled-componentsandapp-dir-i18n-routingexamples, pinned to a release tag. It runs without a config file, the way a first run on a real app does, and with--fail-on warning: the apps are expected to be clean, so any finding above info is a false positive to investigate.
A tool that only works on its own fixtures is not a tool, which is why the second workflow matters most.
What is stable
- CLI: Commands, flags and exit codes keep their meaning. New flags may be added.
- Config: Documented options and
configVersion: 1are stable. A removal or rename requires a major release, andhydration-proof migratekeeps working for at least one major version. - JSON report:
report.jsonusesschemaVersion: 1, described byschema/report.json. Fields may be added, but not removed or repurposed. - Issue codes: An
HPxxxxcode keeps its meaning and is never reused. - Fingerprints: Stable within a
fingerprintVersion, so baselines and ignore rules keep matching. - Node API:
run(),defineConfig,definePlugin,defineAdapter,mergeReports,ISSUESand their types. - Plugin and adapter API: The fields described on the plugins and adapters pages.
- Reporter output: JUnit, SARIF and GitLab output follow their schemas.
The issue codes and CLI pages list the stable values.
What is not stable
These are internals. They change in minor releases, and nothing outside the package should depend on them:
- everything the public exports do not re-export, including the capture stages, the mutation log, the rewind and the diff
- the browser runtime and its protocol, which is rebuilt and inlined on every release (both sides always ship together)
- the HTML report's markup and its embedded data
- the exact wording of messages, the set of
evidenceentries, and confidence scores - which cause a finding is given, and whether it has a cause at all. Diagnosis improves over releases, so treat a cause as an explanation for a human, not as something to assert on
severity is in between: a code's severity can be lowered or raised in a
minor release when experience shows it was wrong. Pin the behavior you care
about with ci.failOn and ci.budget rather than relying on the defaults.
Baselines and budgets shows how.
Fingerprints and baselines
A fingerprint identifies a finding across runs, so a baseline recorded today still matches tomorrow. It is built from the issue code, the route pattern, the scenario and the element's position. It never uses values that change per request, or anything redaction rewrites: fingerprints are computed first.
If a fix has to change how fingerprints are computed, fingerprintVersion in
the report is raised, the release notes say so, and hydration-proof baseline
rewrites your baseline. Old baselines keep working until you record them again:
entries with an older fingerprintVersion are matched by code, route and
selector instead.
How deprecation works
When something stable has to go:
- It keeps working, and using it prints a note that names the replacement.
hydration-proof migraterewrites it where a rewrite is possible.- It is removed in the next major release at the earliest.
Config options are the common case, and migrate covers them. Nothing is ever
removed in a patch release.
Upgrading
List what the new version renamed or replaced, then apply the safe renames:
npx hydration-proof migrate
npx hydration-proof migrate --write--write keeps the old file as <file>.backup. Changes that need a judgment
call are listed for you to make by hand.
Between minor versions, expect new findings: better detection is the point. If
a release reports something you have decided to live with,
an ignore rule with a reason and an expiry date is the honest
way to park it. ci.newIssuesOnly (--new-only) lets you adopt a release
without a red pipeline on day one.
Related
- Release notes
- Node API: the stable programmatic surface
- Reports: the
report.jsonschema and other formats - Troubleshooting
- Quick start