A Next.js date hydration error happens when a component reads the current time while it renders: the server renders at one moment, the browser hydrates a few hundred milliseconds (or, for a cached page, days) later, and the text no longer matches. Pass the time the server used as a prop, or read the clock after the page has hydrated.
Symptoms
The same bug shows up under several names, depending on the React version and the build:
Hydration failed because the server rendered text didn't match the client.
Text content does not match server-rendered HTML.
Warning: Text content did not match. Server: "12:04:31" Client: "12:04:33"
Minified React error #418; visit https://react.dev/errors/418hydration-proof reports it as HP1001 (text) or
HP1002 (an attribute such as datetime), with the cause
Time-dependent value. In the package's own test suite that cause is
identified with 97% confidence.
A date hydration error that only appears on some visits usually means the value is rounded ("3 minutes ago"): the two renders differ only when they fall on either side of a boundary.
Why it happens
Any of these in render code produces a new value on each render:
Date.now(),new Date()andDate()with no argumentsperformance.now()andTemporal.Now.*()- relative formatting built on them: "3 minutes ago", countdowns, "today"
React compares the first client render with the server HTML. A new Date() hydration mismatch or a Date.now() hydration mismatch is guaranteed as soon as the clock moves between the two renders, and it always does.
How to fix it
Pass the server's time as a prop
Read the clock once, on the server, and send the value to the client. Both renders then use the same number:
// A Server Component: it only renders on the server.
export default async function Page() {
const post = await getPost();
return <PostDate publishedAt={post.publishedAt} renderedAt={Date.now()} />;
}"use client";
export function PostDate({
publishedAt,
renderedAt,
}: {
publishedAt: number;
renderedAt: number;
}) {
const minutes = Math.round((renderedAt - publishedAt) / 60_000);
return <p>Updated {minutes} minutes ago</p>;
}Render the time after hydration
When the value must be live (a clock, a countdown), render a placeholder on the server and fill it in from an effect. Effects never run on the server, so the first client render still matches:
"use client";
import { useEffect, useState } from "react";
export function Countdown({ endsAt }: { endsAt: number }) {
const [now, setNow] = useState<number | null>(null);
useEffect(() => {
setNow(Date.now());
const id = setInterval(() => setNow(Date.now()), 1000);
return () => clearInterval(id);
}, []);
if (now === null) return <span>–</span>;
return <span>{Math.round((endsAt - now) / 1000)}s left</span>;
}useEffect and two-pass rendering explains the pattern and when the flash of the placeholder matters.
Format a fixed date, not "now"
A date built from a stored value is deterministic: new Date(post.publishedAt)
is the same on both sides. It can still differ if you format it in the reader's
timezone or locale; see timezone and
locale differences for that half of the problem.
How to solve hydration errors related to dates in React without hiding them
suppressHydrationWarning on the element that shows the time makes React keep
the server text without reporting it. That is acceptable for a live clock
whose first value does not matter, and wrong everywhere else: the page shows
the server's stale value until the next render. See
when suppressHydrationWarning is safe.
Catch it with ESLint
no-date-in-render reports Date.now(),
new Date(), performance.now() and Temporal.Now in render code, and skips
Server Components with the next preset:
npm install -D eslint-plugin-hydration-proofno-timezone-without-explicit-timezone
catches the formatting half.
Catch it in CI
hydration-proof test loads every route and reports each time-dependent value
as HP1001 or HP1002. With --probe, it reloads the page with the browser clock
moved by 3 days, 7 hours, 11 minutes and 13 seconds; if the client value
changes, the cause is proven rather than guessed. See probes.
npx hydration-proof test --probe