Text Content Does Not Match
Server Rendered HTML — Complete Fix
Next.js 15 • React 19 • TypeScript • Vite • React Router • Redux Toolkit
📝 What Does “Text Content Does Not Match Server Rendered HTML” Mean?
The “Text content does not match server-rendered HTML” warning is a specific type of hydration error that occurs when the text content of an element differs between what was rendered on the server and what React renders on the client during the first pass.
The full warning message reads:
Warning: Text content did not match. Server: "Hello, World!" Client: "Hi, World!"
See more info at: https://nextjs.org/docs/messages/react-hydration-error
Why does this happen? This error is triggered when:
- You render dynamic text that depends on client-only data (e.g.,
new Date(), user preferences). - You use conditional text that differs between server and client.
- You access
window,localStorage, or other browser APIs during render. - You have environment-specific text (e.g.,
process.env.NODE_ENV). - You use third-party content that changes between server and client.
⚡ Quick Reference — Common Causes at a Glance
new Date().toString() differs between server and client.localStorage.getItem('name') or user preferences.{isClient ? 'Client' : 'Server'} condition.process.env.NODE_ENV or other env variables.📋 Golden Rules to Avoid Text Mismatch Errors
-
Never render dates/timestamps directly — Use
useEffectoruseStatewith hydration. -
Never access
localStorageorsessionStorageduring render — UseuseEffect. -
Use the
'use client'directive — In Next.js 15, mark client-only components explicitly. -
Use
suppressHydrationWarningsparingly — Only for unavoidable text mismatches. -
Use
next/dynamicwith{ ssr: false }— For text that should only render on the client. - Use stable, deterministic values — Ensure the same text is generated on server and client.
🧩 Detailed Breakdown — Every Scenario Solved
Each card below dives deep into one specific cause of the text mismatch error, with root causes, code examples, and step-by-step fixes.
🛡️ Prevention — Avoid Text Mismatch Errors Forever
Use
useEffect to set date strings after hydration, or use
suppressHydrationWarning for timestamps.
useEffect for Client-Only TextAny text that depends on the client (user name, preferences, screen info) should be set in
useEffect after hydration.
'use client' DirectiveIn Next.js 15, mark components that render client-specific text as client components.
next/dynamic with { ssr: false }For components that render text from browser APIs, disable SSR entirely.
suppressHydrationWarning SparinglyOnly use this attribute when the text mismatch is truly unavoidable and harmless.
use hook with
promises for data fetching in server components, but ensure the data is the same
on both server and client.
❓ Frequently Asked Questions
Even with the same data source, text can mismatch due to:
- Time differences —
new Date()runs at different times on server and client. - Locale differences — Server and client may have different locales.
- Serialization issues — Data might be serialized differently (e.g.,
undefinedbecomesnull). - Whitespace differences — Extra spaces or line breaks in HTML.
The key is to ensure that the exact same text string is generated on both server and client.
suppressHydrationWarning on text elements?
Yes. You can add suppressHydrationWarning to
any element, including text-containing elements like <span>,
<div>, or <p>.
// ✅ Suppress warning for timestamp
<span suppressHydrationWarning>
{new Date().toLocaleString()}
</span>
No. React 19 has the same text hydration rules as React 18. The warning and its behavior remain unchanged.
React 19's new use hook for promises can help with data fetching,
but the text must still match between server and client.
Best practices for debugging:
- Check the console — Next.js shows the exact server and client text values.
- Use React DevTools — Inspect the component tree and see which elements are mismatching.
- Add temporary logging — Log the text value on both server and client.
- Use
suppressHydrationWarningtemporarily to identify the culprit. - Use
next build && next startto test production-like behavior. - Check for browser APIs — Search for
window,document,localStoragein your components.
Common Redux Toolkit causes:
- Initial state differs between server and client.
- State depends on browser APIs (
window,localStorage). - Hydration of persisted state from
localStorage.
Fix:
// ✅ Correct — hydrate Redux state on client
function ReduxProvider({ children }) {
const [isClient, setIsClient] = useState(false);
useEffect(() => {
setIsClient(true);
}, []);
// Only load persisted state on client
const store = useMemo(() => {
const preloadedState = isClient
? loadStateFromLocalStorage()
: undefined;
return configureStore({
reducer: rootReducer,
preloadedState,
});
}, [isClient]);
return <Provider store={store}>{children}</Provider>;
}
Yes. Markdown or HTML content can cause text mismatches if:
- The content is generated differently on server and client.
- Whitespace or line breaks differ between server and client.
- The content includes timestamps or dynamic values.
Solutions:
- Use the same markdown parser on both server and client.
- Use
dangerouslySetInnerHTMLwithsuppressHydrationWarningif needed. - Use
next/dynamicwith{ ssr: false }for markdown content.
// ✅ Correct — markdown with SSR
import ReactMarkdown from 'react-markdown';
function MarkdownContent({ content }) {
// content is the same on server and client
return <ReactMarkdown>{content}</ReactMarkdown>;
}
0 Comments
thanks for your comments!