React 19 hydration mismatch: the date that formats differently on server and client
verbatim errorUncaught Error: Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client.
Problem
Next.js (App Router, React 19) started throwing on a page that renders an order list:
Uncaught Error: Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client.The page still worked (React rebuilt it client-side), which made it easy to ignore — until we noticed the flash of unstyled content and a Lighthouse hydration-related penalty.
Root cause
The server rendered new Date(order.createdAt).toLocaleDateString('en-US') in UTC on the Node box; the client re-rendered it with the visitor's timezone and locale. Same code, different environment, different string. Classic causes of this class:
Date,Intl,toLocaleDateString— locale/timezone dependentMath.random(),crypto.randomUUID(),Date.now()— nondeterministic per render- reading
window.localStorageduring the initial render - browser-only value in JSX that differs from server-rendered markup
fix preview — first 3 of 6 lines (tsx), truncated:
import { formatInTimeZone } from 'date-fns-tz';
const fmt = (iso: string) =>
… 3 more lines in the fix🔒 the fix — including 2 code blocks — is members-only. $1/mo unlocks everything.