
Amit Hariyale
Full Stack Web Developer, Gigawave
The Complete Guide to Solving the 'Text content does not match' Warning
Full Stack Web Developer, Gigawave
Hydration errors are among the most common and frustrating issues in Next.js development. These errors occur when there's a mismatch between server-rendered HTML and client-side JavaScript. This guide will help you understand why they happen and how to fix them permanently.
You've probably seen this warning in your console:
1Warning: Text content did not match. Server: "Hello" Client: "World"
2Uncaught Error: Hydration failed because the initial UI does not match what was rendered on the server.
The Hydration Process | The hydration process in Next.js involves the following steps: |
---|---|
Server Rendering | Next.js generates HTML on the server |
Initial Hydration | React attaches event handlers to server HTML |
Mismatch Detection | React compares server and client output |
Error Thrown | Differences trigger hydration error |
Hydration is React's process of attaching to server-generated HTML and making it interactive.
Accessing window
or document
directly during server rendering:
1// ❌ Wrong: Accessing window during render
2function BrokenComponent() {
3 const width = window.innerWidth; // Server: undefined, Client: 1200
4 return <div>Width: {width}px</div>;
5}
1// ✅ Fixed: Use useEffect + useState
2function FixedComponent() {
3 const [width, setWidth] = useState(0);
4
5 useEffect(() => {
6 setWidth(window.innerWidth);
7 const handleResize = () => setWidth(window.innerWidth);
8 window.addEventListener('resize', handleResize);
9 return () => window.removeEventListener('resize', handleResize);
10 }, []);
11
12 return <div>Width: {width}px</div>;
13}
Formatting dates differently on server and client:
1// ❌ Wrong: Inconsistent formatting
2function DateComponent() {
3 const date = new Date().toLocaleDateString();
4 // Server: "7/5/2025", Client: "05/07/2025" (different locales)
5 return <div>Today: {date}</div>;
6}
1// ✅ Fixed: Use consistent timezone/locale
2function FixedDateComponent() {
3 const [date, setDate] = useState('');
4
5 useEffect(() => {
6 setDate(new Date().toLocaleDateString('en-US'));
7 }, []);
8
9 return <div>Today: {date}</div>;
10}
Libraries that aren't SSR-compatible:
1// ❌ Wrong: Directly using non-SSR library
2import { Map } from 'non-ssr-map-library';
3
4function LocationMap() {
5 return <Map center={[51.505, -0.09]} />; // Fails on server
6}
1// ✅ Fixed: Dynamic import with no SSR
2import dynamic from 'next/dynamic';
3
4const Map = dynamic(() => import('non-ssr-map-library').then(mod => mod.Map), {
5 ssr: false
6});
7
8function FixedLocationMap() {
9 return <Map center={[51.505, -0.09]} />;
10}
For safe differences (like unimportant whitespace):
1// Add suppressHydrationWarning to ignore specific differences
2<div suppressHydrationWarning={true}>
3 {new Date().toLocaleTimeString()}
4</div>
For DOM measurements that need to happen before paint:
1import { useLayoutEffect, useRef } from 'react';
2
3function MeasureComponent() {
4 const ref = useRef(null);
5
6 useLayoutEffect(() => {
7 const { width } = ref.current.getBoundingClientRect();
8 console.log('Width:', width);
9 }, []);
10
11 return <div ref={ref}>Content</div>;
12}
Hydration Error Checklist | Common issues that cause hydration errors |
---|---|
Browser APIs | Moved to useEffect/useLayoutEffect |
Dates/Times | Consistent formatting on server/client |
External Libraries | Using dynamic imports with ssr:false |
State Initialization | Consistent initial values |
CSS-in-JS | Proper server-side rendering config |
Hydration errors can be tricky, but understanding their root causes makes them much easier to solve. Remember that consistency between server and client rendering is key - when in doubt, move browser-specific logic to useEffect or useLayoutEffect hooks.
By following these patterns and best practices, you'll eliminate hydration errors and create more robust Next.js applications with smoother user experiences.