These are the ESLint rules for React hydration in
eslint-plugin-hydration-proof: 15 rules, each for one way the server render
and the browser's first render can differ. Every rule is on in all three
presets; the presets change only the severity and whether Server Components
are checked. Install the plugin to use them.
All ESLint rules for React hydration
| Rule | What it reports | recommended | strict |
|---|---|---|---|
| no-date-in-render | Disallow reading the current time while a component renders | Error | Error |
| no-random-in-render | Disallow random values while a component renders | Error | Error |
| no-browser-global-in-render | Disallow reading browser-only globals such as window and document while a component renders | Error | Error |
| no-storage-in-initial-render | Disallow reading localStorage or sessionStorage while a component renders, including state initializers | Error | Error |
| no-match-media-in-render | Disallow evaluating media queries with matchMedia while a component renders | Error | Error |
| no-locale-without-explicit-locale | Require an explicit locale for locale-sensitive formatting during render | Warning | Error |
| no-timezone-without-explicit-timezone | Require an explicit timeZone when dates are formatted or split into parts during render | Warning | Error |
| no-unstable-id | Disallow ids built from random values, the clock or module-level counters | Error | Error |
| no-global-render-counter | Disallow changing module-level variables while a component renders | Error | Error |
| no-window-render-branch | Disallow rendering different output depending on whether the code runs on the server or in the browser | Error | Error |
| no-invalid-interactive-nesting | Disallow HTML nesting that the browser repairs while parsing, such as <div> in <p> or <a> in <a> | Error | Error |
| audit-suppress-hydration-warning | Report suppressHydrationWarning where it has no effect or hides more than intended | Error | Error |
| no-client-only-initial-state | Disallow initial state and refs computed from browser-only values | Warning | Error |
| require-stable-server-snapshot | Require useSyncExternalStore to have a getServerSnapshot that returns the same value on the server and during hydration | Error | Error |
| require-deterministic-list-order | Require list ordering during render to be the same on the server and in the browser | Warning | Error |
Each rule page shows what it reports, why it breaks hydration, code the rule reports and code it accepts, its options and its exact messages.
What each group of rules catches
Time and random values
no-date-in-render reports Date.now(),
new Date(), performance.now() and Temporal.Now in render code.
no-random-in-render reports
Math.random(), crypto.randomUUID(), uuid, nanoid and lodash's random
helpers. Both values change between the server render and hydration; see
time and random values.
Browser-only values
The server has no window, storage or screen, so anything read from them
renders differently on each side:
no-browser-global-in-render:window,document,navigator,location,innerWidthand the other browser globalsno-storage-in-initial-render:localStorageandsessionStorage, including state initializersno-match-media-in-render:matchMedia()media queriesno-window-render-branch:typeof windowchecks andisServer-style flags that change the outputno-client-only-initial-state: browser values in the initial value ofuseState,useReducer,useRefand class state
The matching fix guides are browser-only APIs, storage and media queries.
Locale, time zone and list order
no-locale-without-explicit-locale:toLocaleString(),localeCompare()andIntl.*without a localeno-timezone-without-explicit-timezone: date formatting withouttimeZone, and local-time getters such asgetHours()require-deterministic-list-order: random or locale-dependent sorting, boolean comparators andshuffle
These are warnings in recommended, because the output only differs when the
server and the visitor use a different locale or
time zone.
Ids and counters
no-unstable-id reports random, time-based or
counter ids where useId() belongs.
no-global-render-counter reports
module-level variables changed during render, which keep counting on the
server across requests. See generated ids that differ.
Markup
no-invalid-interactive-nesting
reports <div> in <p>, <a> in <a>, <button> in <button> and table
rows outside <tbody>: nesting the browser repairs before React hydrates
(invalid HTML).
audit-suppress-hydration-warning
reports suppressHydrationWarning that does nothing or covers too much
(suppressed differences). Both also check Server
Components: React hydrates the elements a Server Component renders, and the
root layout, where <html suppressHydrationWarning> lives, is one.
useSyncExternalStore
require-stable-server-snapshot
reports useSyncExternalStore without a getServerSnapshot, and a
getServerSnapshot that reads the browser, the clock or random values. It is
the rule behind the fix several other rules recommend.
Presets
| Preset | Severity | Server Components |
|---|---|---|
recommended | Definite mismatches are errors; locale, time zone, initial state and list order are warnings. | Checked (the setting defaults to 'none') |
next | Same as recommended. | Files under app/ without 'use client' are skipped |
strict | Every rule is an error, and every suppressHydrationWarning needs a reason (reportAll: true). | Checked unless you add the setting |
Set up a preset shows the config for each, and one report per problem explains which rule reports a construct when two could.