One command, every route
A hydration mismatch detector that loads each page in Chromium, Firefox or WebKit, not a simulation.
A hydration error checker for Next.js, React Router, Remix and Astro: a real browser compares your server HTML with the hydrated DOM on every route, then tells you what differs, why, and how to fix it. The ESLint plugin catches the same mistakes while you type.
npm install -D hydration-proof eslint-plugin-hydration-proofNext.js · React Router · Remix · Astro · ViteReact 18 and 190 bytes in your bundleMIT
One finding, followed from the terminal to the pull request: the server HTML, the hydrated DOM, the likely cause and the ESLint rule that would have caught it.
A hydration mismatch detector that loads each page in Chromium, Firefox or WebKit, not a simulation.
15 ESLint rules flag Date.now(), Math.random(), window, localStorage and invalid nesting in render.
Server HTML next to the hydrated DOM: text, attributes, classes, styles and repaired markup.
A likely cause with a confidence, proven by reloading with one thing changed, and the fix.
GitHub annotations on the line, a job summary, SARIF, JUnit and GitLab reports.
$ npx hydration-proof test Hydration Proof — 4 pages on http://localhost:3000 ✓ / 412ms ✓ /pricing 388ms ✖ /blog/hello-world 1.2s 1 error HP1001 Text differs between server and client (time-dependent value, 97%) #published-at in PostDate server: "Updated 12:04:31" client: "Updated 12:04:33" app/blog/[slug]/post-date.tsx:12:18 → Render exactly the same text on the server and in the first client render. ✓ /docs 402ms Pages tested: 4 Passed: 3 Warnings: 0 Failed: 1 Duration: 3.9s ✖ 1 issue at or above "error" severity. Report: .hydration-proof/report/report.html
export function PostDate() { const now = Date.now(); return <p>{format(now)}</p>; }
hydration-proof/no-date-in-render
Date.now() reads the clock during render. The server renders one time and the browser another while hydrating, so the output does not match. Pass the time from the server (props or data), or read it in useEffect after hydration.
HP1001Text differs between server and client
Server HTML
<p id="published-at"> Updated 12:04:31 </p>
After hydration
<p id="published-at"> Updated 12:04:33 </p>
Likely cause
Time-dependent value
Proven by a probe
Reloaded with the browser clock moved +3d 7h 11m 13s: the text changed again.
Source
app/blog/[slug]/post-date.tsx:12
How to fix
The server and the browser render at different moments. Pass the timestamp the server used as a prop, or render the time after mount (useEffect).
❌ Hydration Proof: 1 page failed
app/blog/[slug]/post-date.tsx#L12
Page: /blog/hello-world Element: #published-at Server: "Updated 12:04:31" Client: "Updated 12:04:33" Likely cause: Time-dependent value (97% confidence) Fix: Render exactly the same text on the server and in the first client render.
Also written as SARIF for code scanning, JUnit, GitLab Code Quality and a single-file HTML report.