Fixing Astro hydration mismatch errors
Astro & static sites · updated aug 2026
A hydration mismatch in an Astro island means the HTML the server rendered doesn’t match what the client-side framework expects to find when it hydrates, and the framework either patches over the difference in a way you didn’t want or throws a warning and re-renders the whole thing. Either way it’s a sign something isn’t deterministic between server and client, not a framework bug.
The most common cause on real projects is anything that depends on Date, Math.random(), or browser-only globals inside a component that also renders on the server. new Date().toLocaleDateString() formatted at render time produces a different string on the server than it does if the client re-evaluates it, especially across timezones. Same with anything reading window or document directly in the component body rather than inside a lifecycle hook that only runs client-side — the server has no window, so either it throws or a guard produces different output than the client branch does.
The second common cause is conditional rendering based on something that differs between environments — a feature flag read from localStorage, a viewport check using window.innerWidth, anything that branches on client-only state during the initial render. The server renders one branch, the client evaluates a different one on hydration, and the framework sees mismatched trees.
To actually track down which one you have: check the browser console first, most frameworks log which node or attribute didn’t match, and that’s usually specific enough to point at the offending line without guessing. If the warning is vague, bisect by commenting out sections of the component until the warning disappears, then look at what’s left for anything reading a browser global, using Date/Math.random() directly in render, or branching on localStorage/cookies without a server-side equivalent.
The fix pattern is almost always the same: move anything non-deterministic out of the initial render and into a client-only effect, so the server renders a neutral default and the client updates it after hydration rather than trying to make the two renders match up front. For a date display, render a static or server-computed value first, then update it client-side in onMount if you need it to reflect the visitor’s local timezone. It’ll flash from one value to the other on load, which is the tradeoff — but it’s a visible, expected flash instead of a hydration warning and a wasted re-render.
builder, codelabs.com.au
Stay up to date with AI coding
New articles roughly every couple of weeks. No spam, unsubscribe any time.