The eslint-plugin-react-hooks purity rule reports calls to known impure functions, such as Date.now() and Math.random(), while a component renders. It protects re-renders and memoization. eslint-plugin-hydration-proof targets hydration: 15 rules for values that differ between the server and the browser, including code the purity rule accepts. The two overlap on the clock and random values, and run fine together.
At a glance
| The purity rule | eslint-plugin-hydration-proof | |
|---|---|---|
| Goal | Components and hooks are pure, so re-renders and memoization are safe | The server render and the hydration render produce the same output |
| Comes with | The recommended preset of eslint-plugin-react-hooks 7, and eslint-config-next | Its own recommended, next and strict presets |
| Clock and random values | Date.now(), Math.random(), performance.now() in 7.1.1 | Those, plus new Date(), crypto.randomUUID(), uuid, nanoid, lodash and more |
Lazy useState initializers | Accepted | Reported: the initializer runs on the server and again during hydration |
| Locale and timezone formatting | Not checked | toLocaleString(), Intl.* and date getters without an explicit locale or timezone |
Browser APIs, storage, matchMedia | Not checked | Reported in render and initial state |
| Invalid HTML nesting | Not checked | <div> in <p>, <a> in <a>, table structure |
suppressHydrationWarning | Not checked | Audited |
| Server Components | No special handling | Skipped by the next preset, where the clock cannot cause a mismatch |
| Message | Why the call is impure | What the server and the browser render, and the fix |
What the eslint-plugin-react-hooks purity rule does well
react-hooks/purity is one of the React Compiler's rules, now shipped in eslint-plugin-react-hooks. React's docs say it "validates that components/hooks are pure by checking that they do not call known-impure functions" (purity). It reports:
Error: Cannot call impure function during render
`Date.now` is an impure function. Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render.- It is on by default.
purityis in therecommendedpreset of eslint-plugin-react-hooks 7, andeslint-config-nextincludes that preset, so Next.js apps that use it already run the rule. - It sees data flow. It runs the compiler's analysis, not a pattern match.
- It covers more than hydration. Impure renders break memoization and the React Compiler, not only server rendering. Its docs name hydration mismatches as one of the bugs impurity causes.
The React Compiler's lint rules used to live in a separate package, eslint-plugin-react-compiler. React's Compiler 1.0 announcement says to remove it and use eslint-plugin-react-hooks@latest instead.
Where hydration-proof differs
Pure is not the same as hydration-safe. Purity asks whether a render gives the same result every time it runs in one place. Hydration asks whether the server and the browser give the same result. The purity docs show this as the valid way to create an id:
import { useState } from "react";
function Item() {
// Stable across re-renders, so react-hooks/purity accepts it.
// The server and the browser each run the initializer once, and get
// different UUIDs: the hydration render does not match the server HTML.
const [id] = useState(() => crypto.randomUUID());
return <div id={id}>Content</div>;
}eslint-plugin-hydration-proof reports it (no-unstable-id), because lazy initializers run during the first render on both sides. The same goes for useState(() => Date.now()), which the purity docs use for a clock: fine for re-renders, a guaranteed mismatch during hydration.
More causes than the clock. Many hydration mismatches never call an impure function:
no-locale-without-explicit-localeandno-timezone-without-explicit-timezone: formatting that depends on the machine;no-browser-global-in-render,no-storage-in-initial-render,no-match-media-in-renderandno-window-render-branch: code that sees the browser;no-invalid-interactive-nesting: HTML the browser repairs;require-stable-server-snapshotandaudit-suppress-hydration-warning.
new Date(). In eslint-plugin-react-hooks 7.1.1, the compiler marks Date.now, Math.random and performance.now as impure. A reported gap was that new Date().getTime() and new Date().getFullYear() were not flagged; the fix, which treats new Date() without arguments as impure, was merged on September 15, 2026 and is not in a stable release yet. no-date-in-render reports new Date(), Date() and Temporal.Now today.
Server Components. With the next preset, eslint-plugin-hydration-proof skips Server Components, where reading the clock cannot cause a mismatch because the browser receives the result, not the code.
Use both
Keep the purity rule for what it protects, and add eslint-plugin-hydration-proof for hydration:
import { defineConfig } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import hydrationProof from "eslint-plugin-hydration-proof";
export default defineConfig([...nextVitals, hydrationProof.configs.next]);A Date.now() or Math.random() in render is then reported twice, once by each plugin, with different reasons. Keep both reports, or turn one of the overlapping rules off. The ESLint plugin guide covers presets and settings.
npm install -D eslint-plugin-hydration-proofA linter reads one file at a time. Values passed through props or context, nesting across components, CSS-in-JS and anything that happens outside your code need hydration-proof test, which checks the running app.
Sources
As of September 2026:
- react.dev: purity and eslint-plugin-react-hooks, the rule and the
recommendedpreset - eslint-plugin-react-hooks 7.1.1 on npm, the message text and the impure functions in its source
- facebook/react#37553 and facebook/react#37576,
new Date()in the purity rule - Next.js: ESLint plugin,
eslint-config-nextincludes therecommendedrules of eslint-plugin-react-hooks - React Compiler 1.0,
eslint-plugin-react-compilerreplaced by eslint-plugin-react-hooks