hydration-safetylisted
Install: claude install-skill soumit-kaz/lazysitter
# Hydration safety
## What a mismatch actually costs
The server renders HTML; the client renders the same tree and attaches to it. If the two disagree, React discards the server HTML for that subtree and re-renders on the client. That means: **lost server-rendering benefit, a visible flash, effects firing again, and any state initialized from the server markup going wrong.** It is not a cosmetic warning.
Worse, mismatches are frequently **invisible in development** — same machine, same timezone, same locale, same clock — and appear only in production across real users.
```bash
lazysitter fe-index signals --rule HYDRATE-NONDETERMINISTIC
```
finds the mechanical candidates. They are heuristic — confirm each by reading.
## The five causes, in order of frequency
### 1. Time and randomness in render
`Date.now()`, `new Date()`, `Math.random()`, a generated id. The server evaluates at request time, the client milliseconds later, and the values differ.
Fixes: compute on the server and pass the value down as a prop · compute in an effect after mount (accepting a first paint without it) · use React's `useId` for generated ids, which is built to be stable across the boundary.
### 2. Browser-only APIs during render
`window`, `document`, `localStorage`, `navigator`, `matchMedia`. On the server they are undefined; guarding with `typeof window !== 'undefined'` **inside render** does not fix the mismatch — it *guarantees* one, because the two environments then take different branches