Next.js: Hydration failed because the server rendered HTML didn't match the client
Hydration failed — server/client HTML mismatch
Verified against Next.js 16 docs (messages/react-hydration-error), React 19 docs (link-a-react-component-errors), Stack Overflow #68945655 · Updated April 2026
> quick_fix
Something in your component renders differently on the server vs the first client render. Top suspects: new Date(), Math.random(), window.*, localStorage, or invalid HTML nesting (div inside p, etc.). Move client-only code into useEffect or gate it with a useState flag.
'use client'
import { useEffect, useState } from 'react'
// ❌ Mismatches
function Clock() {
return <p>{new Date().toLocaleString()}</p>
}
// ✅ Client-only render after mount
function Clock() {
const [time, setTime] = useState('')
useEffect(() => {
setTime(new Date().toLocaleString())
}, [])
return <p suppressHydrationWarning>{time}</p>
}What causes this error
Next.js renders your components on the server, sends the HTML, and then React hydrates by re-rendering the component tree on the client and comparing to the existing DOM. If the first client render produces different markup, React logs this error and falls back to client-only rendering — slow and janky.
How to fix it
- 01
step 1
Open DevTools and find the mismatch
The console error lists the expected vs received text. Search your codebase for that text or the surrounding component name.
- 02
step 2
Isolate non-deterministic values
Date.now, Math.random, window.*, navigator.language, navigator.userAgent, locale-dependent formatting — all render differently on server vs client. Move them to useEffect.
- 03
step 3
Check for invalid HTML nesting
<div> inside <p>, <p> inside <p>, or <a> inside <button> — the browser auto-corrects these on the client and diverges from server HTML. Fix the nesting.
- 04
step 4
For genuinely dynamic values, use suppressHydrationWarning
React's escape hatch. Only use on single text nodes you know will diverge intentionally.
- 05
step 5
For complex client-only components, use dynamic import
next/dynamic with ssr: false disables server rendering for that component entirely — the right choice for things like a Leaflet map that must be client-only.
import dynamic from 'next/dynamic' const Map = dynamic(() => import('./Map'), { ssr: false })
Frequently asked questions
What does hydration mean in Next.js?
Hydration is the process where React re-uses the HTML sent by the server and attaches event handlers and state, without rebuilding the DOM from scratch. Fast; requires the first client render to match the server.
Does hydration mismatch crash my app?
Not always — React falls back to client-only rendering for the mismatched subtree. But it's slow, logs an error, and breaks SSR benefits. Fix it.
Can I disable SSR for a specific page?
Yes — use `export const dynamic = "force-dynamic"` or wrap the whole page in `next/dynamic` with ssr:false. But this defeats the point of Next.js for that page.