How to Fix the Next.js Hydration Error (Text Content Does Not Match)
The Next.js hydration error "Text content does not match server-rendered HTML" breaks your app silently. Here's what causes it and how to fix it permanently.
What Is a Hydration Error?
When Next.js renders a page, it does it twice: once on the server to send HTML to the browser, and once on the client where React hydrates that HTML to make it interactive. If what React renders on the client does not match what the server sent, you get a hydration mismatch.
Error:
Text content does not match server-rendered HTML. Warning: Expected server HTML to contain a matching <div> in <div>.
This usually shows as a white flash, broken layout, or a full-page re-render. In production it is silent but damages user experience and Core Web Vitals.
The 5 Most Common Causes
1. Date or Math.random() Called During Render
Server renders at request time. Client renders at load time. Any value that changes between those two moments will mismatch.
Move time-dependent values into useEffect so they only run on the client:
2. Browser-Only APIs in Render
window, localStorage, navigator do not exist on the server. If your component reads them during render, the server crashes or returns undefined while the client gets the real value.
Error:
ReferenceError: window is not defined
Move the browser API call to useEffect:
3. Third-Party Scripts That Modify the DOM
Ad scripts, chat widgets, and analytics tools sometimes inject DOM nodes before React hydrates. React then finds unexpected elements and fails.
Warning: Hydration failed because the server rendered HTML did not match the client. The most common reason is that a browser extension modified the HTML before React could hydrate it.
Use the Next.js <Script> component with strategy="lazyOnload" instead of raw <script> tags in _document. This ensures third-party scripts fire after hydration completes:
4. Invalid HTML Nesting
React and the browser both enforce HTML nesting rules. If you nest a <div> inside a <p>, or a <p> inside an <a>, the browser silently fixes it during parsing but React's VDOM does not match the corrected DOM.
Use <div> or <span> consistently. Run your page through the W3C HTML validator if you are not sure.
5. Conditional Rendering Based on typeof window
This pattern looks safe but is not. React tries to reconcile server output where window is undefined with client output where it exists.
Use the mounted pattern instead:
Suppressing vs Fixing
You will find this suggested online:
suppressHydrationWarning hides the error but does not fix it. React still re-renders the whole subtree on the client, causing layout shift. Use it only for values that genuinely cannot be known at SSR time, like browser fingerprints or ad content, and isolate it to a single element.
How to Debug Hydration Errors Fast
Next.js 13+ shows a detailed diff in development mode. Look for this in your terminal or browser console:
The server/client diff tells you exactly which component is mismatching.
Note: In Next.js 14+, hydration errors include a component stack trace in dev mode. Run
next devnotnext startto see the full trace.
Summary
| Cause | Fix |
|---|---|
new Date() or Math.random() in render | Move to useEffect |
window or localStorage access | Guard with useEffect or mounted pattern |
| Third-party DOM scripts | Use <Script strategy="lazyOnload"> |
| Invalid HTML nesting | Fix nesting and validate HTML |
typeof window conditional render | Use mounted state pattern |
Hydration errors are always a server/client mismatch. Find what is different between the two environments and defer the client-only part to useEffect. For complex component trees where the mismatch source is not obvious, paste the error and component into DebugAI and it will trace the exact render path causing the diff.
Debug faster starting today.
Free VS Code extension. 10 sessions/day. No credit card.