This error occurs during hydration when the HTML rendered on the server doesn't match what React renders on the client. Common causes include dynamic content like dates, timestamps, random values, or browser-specific APIs. Fix it by ensuring consistent rendering between server and client, or use suppressHydrationWarning for unavoidable mismatches.
React uses a process called hydration to attach interactivity to server-rendered HTML. When React initializes on the client side, it expects the DOM structure to match exactly what was rendered on the server. If the text content differs—even by a single character—React detects this mismatch and logs a warning. This happens because server-side and client-side renders must produce identical output for hydration to work correctly. The error indicates that some content changed between the server render and the client render, which can lead to unexpected behavior, visual flickering, or event handler misalignment.
Open your browser DevTools console and look for the full warning message. It will show you exactly what the server rendered vs what the client rendered. This tells you which component or text node has the mismatch.
Warning: Text content did not match.
Server: "Generated at 2024-01-15T10:30:45.123Z"
Client: "Generated at 2024-01-15T10:30:47.456Z"The warning typically includes the component name or approximate location in the DOM.
Search your component for Date.now(), new Date(), or date formatting functions. These are the most common cause because they produce different values each time they run.
// BAD: Different values on server vs client
function Timestamp() {
return <div>{new Date().toISOString()}</div>;
}
// GOOD: Use useEffect to render only on client
function Timestamp() {
const [time, setTime] = useState<string | null>(null);
useEffect(() => {
setTime(new Date().toISOString());
}, []);
return <div>{time || 'Loading...'}</div>;
}Search for Math.random(), UUID generation, or any randomization. Like timestamps, these produce different output each render.
// BAD: Different ID each render
function Card() {
const id = Math.random().toString();
return <div id={id}>Content</div>;
}
// GOOD: Generate ID on server and pass as prop
function Card({ id }: { id: string }) {
return <div id={id}>Content</div>;
}Look for checks like typeof window !== 'undefined' or typeof document !== 'undefined' that conditionally render different content. The server won't execute this code, but the client will.
// BAD: Server renders null, client renders content
function ClientContent() {
if (typeof window === 'undefined') return null;
return <div>{localStorage.getItem('theme')}</div>;
}
// GOOD: Defer to useEffect
function ClientContent() {
const [theme, setTheme] = useState<string | null>(null);
useEffect(() => {
setTheme(localStorage.getItem('theme'));
}, []);
return <div>{theme}</div>;
}Look for Intl.DateTimeFormat, toLocaleString(), or locale-aware number/date formatting. The server may use UTC while the client uses the browser's timezone.
// BAD: Different timezone on server vs client
function DateDisplay({ date }: { date: Date }) {
return <div>{date.toLocaleString()}</div>;
}
// GOOD: Format the date on the server before sending it
function DateDisplay({ formatted }: { formatted: string }) {
return <div>{formatted}</div>;
}
// Usage in a Server Component (Next.js)
export default function Page() {
const formatted = new Date().toLocaleString('en-US');
return <DateDisplay formatted={formatted} />;
}Ensure that any props passed to components don't change between server render and client hydration. If data is fetched at runtime, it must be the same on both sides.
// BAD: API call happens after server render
function UserGreeting() {
const [user, setUser] = useState<string>('');
useEffect(() => {
fetchUser().then(u => setUser(u.name)); // Server rendered '', client renders actual name
}, []);
return <div>Hello {user}</div>;
}
// GOOD: Pass user data as prop from server
function UserGreeting({ user }: { user: string }) {
return <div>Hello {user}</div>;
}If you have content that genuinely must differ between server and client (like a timestamp of when the page was generated), use suppressHydrationWarning to suppress the warning for that specific element.
function PageGeneratedTime() {
const [time, setTime] = useState<string | null>(null);
useEffect(() => {
setTime(new Date().toISOString());
}, []);
return <div suppressHydrationWarning>{time}</div>;
}Important: Use this sparingly. It silences the warning but doesn't fix the mismatch—it just tells React to ignore it for that element. It only works one level deep in the DOM.
Hydration process: React calls ReactDOM.hydrateRoot() on the client, which walks through the server-rendered HTML and attaches event listeners. It does NOT re-render; it reuses the existing DOM. If React detects a mismatch, it logs a warning but typically continues. However, in strict mode, React will re-render the component and replace the HTML, which can cause visual flicker.
Why this matters: Beyond the warning, hydration mismatches can cause subtle bugs where event handlers are attached to the wrong elements, or state is out of sync with the DOM. Always treat these as bugs to fix, not warnings to suppress.
Dynamic imports in Next.js: If you need client-only components, you can use dynamic imports with ssr: false to exclude them from server rendering entirely:
const ClientOnlyChart = dynamic(() => import('./Chart'), { ssr: false });Server Components in Next.js 13+: If using App Router with Server Components, remember that Server Components run only on the server. Use 'use client' directive and useEffect for truly dynamic content that differs between renders.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite