How to Fix: Error: A tree hydrated but some attributes of the server rendered HTML didn’t match the client properties.
Next.js Hydration Error: “A tree hydrated but some attributes of the server rendered HTML didn’t match the client properties”
This error means your server-rendered HTML and the client-rendered React tree are not identical at hydration time. In the reported reproduction, the mismatch is triggered by browser-side changes to the DOM before React hydrates, which makes Next.js warn that some attributes no longer match what it rendered on the server.
Table of Contents
If you want to inspect the original report, see the reproduction repository.
Understanding the Root Cause
Hydration is the process where React attaches event listeners and internal state to HTML already rendered by the server. For hydration to succeed cleanly, the HTML generated on the server must match what React expects to render on the client.
This specific warning appears when something modifies attributes in the DOM between these two moments:
- Next.js sends HTML from the server.
- The browser loads the page.
- Some external agent changes the markup or attributes.
- React hydrates and sees that the DOM no longer matches.
In Chrome, this can happen because of browser extensions, built-in browser features, translation tools, password managers, accessibility tools, auto-fill, or other scripts that inject or rewrite attributes before hydration completes. Even when your application code is correct, those external mutations can still trigger the warning.
Typical examples of hydration mismatches include:
- Rendering values like Date.now() or Math.random() during render.
- Reading window, localStorage, or browser-only state on the first render.
- Conditional markup that differs between server and client.
- Third-party tools injecting attributes such as data markers, accessibility labels, or autofill metadata.
In this issue, the key detail is that opening a new Chrome tab and navigating can involve browser-level behavior that changes attributes before React hydration, so the warning is not always caused by a logic bug in your React component tree.
Step-by-Step Solution
The fix depends on whether the mismatch comes from your code or from external DOM mutation. Start by isolating the source.
1. Verify whether Chrome extensions or browser features are causing the mismatch
Test the app in a clean environment first:
- Open the page in Incognito mode with extensions disabled.
- Try another browser such as Firefox or Safari.
- Disable password managers, translation extensions, accessibility overlays, and DOM-modifying extensions.
If the warning disappears, your app is likely fine and the mismatch is caused by external mutation before hydration.
2. Make sure your initial render is deterministic
Do not render unstable values directly in server components or in the first client render.
// Bad: different output between server and client possible
export default function Page() {
return <p>{Date.now()}</p>
}
// Better: render stable fallback, then update on client
'use client'
import { useEffect, useState } from 'react'
export default function Page() {
const [time, setTime] = useState('')
useEffect(() => {
setTime(String(Date.now()))
}, [])
return <p>{time || 'Loading...'}</p>
}
3. Guard browser-only APIs
If your markup depends on browser APIs, move that logic into useEffect so it only runs after hydration.
// Bad
export default function Page() {
const theme = localStorage.getItem('theme')
return <div>Theme: {theme}</div>
}
// Good
'use client'
import { useEffect, useState } from 'react'
export default function Page() {
const [theme, setTheme] = useState('default')
useEffect(() => {
const value = localStorage.getItem('theme')
if (value) setTheme(value)
}, [])
return <div>Theme: {theme}</div>
}
4. Use suppressHydrationWarning only for known harmless mismatches
If an attribute or text value is expected to differ and cannot reasonably be synchronized, you can suppress the warning for that specific node. This should be a last resort, not the default fix.
export default function Page() {
return <span suppressHydrationWarning>{new Date().toLocaleTimeString()}</span>
}
Use this carefully. It hides the warning but does not solve real rendering bugs.
5. Isolate client-only UI with dynamic import if needed
For components that depend entirely on browser behavior, render them only on the client.
import dynamic from 'next/dynamic'
const ClientOnlyWidget = dynamic(() => import('./ClientOnlyWidget'), {
ssr: false,
})
export default function Page() {
return <ClientOnlyWidget />
}
This avoids server/client mismatch by skipping SSR for that component.
6. Check the actual mismatched element in DevTools
Inspect the warning closely. React often points to the affected subtree. Compare:
- The HTML from View Page Source or server output
- The live DOM in Elements
If you see extra attributes injected by tools you did not write, that confirms an external source.
7. Keep dependencies updated
Hydration warnings can improve across React and Next.js releases. Update to the latest stable versions and retest.
npm install next@latest react@latest react-dom@latest
8. Practical resolution for this issue
For the issue described, the most practical resolution is:
- Confirm the warning in a clean browser profile.
- If it only happens in normal Chrome usage, identify the browser feature or extension mutating the DOM.
- If your own component renders non-deterministic attributes or text, move that logic into useEffect or a client-only component.
- Use suppressHydrationWarning only for intentionally different content such as timestamps.
Common Edge Cases
Browser extensions adding attributes
Extensions frequently inject data-* attributes, inline helpers, grammar markers, or form annotations. These changes can trigger hydration warnings even when your code is valid.
Dark mode or theme initialization
If the server renders one theme and the client immediately switches to another based on local storage or system preference, attributes like class on html or body may mismatch.
'use client'
import { useEffect } from 'react'
export default function ThemeInit() {
useEffect(() => {
const theme = localStorage.getItem('theme')
if (theme) document.documentElement.className = theme
}, [])
return null
}
Use a synchronized theme strategy to avoid flashes and mismatches.
Locale-sensitive formatting
Dates, currencies, and numbers may render differently on the server and client if locales or time zones differ.
// Risky if server and client locale/timezone differ
new Date().toLocaleString()
Pre-format values on the server or format them only after mount.
Random IDs
Generating IDs with Math.random() during render can break hydration. Prefer React-safe patterns or deterministic IDs.
Conditional rendering based on window size
If you render mobile markup on the client and desktop markup on the server, the trees will differ. Use CSS for responsive layout when possible, or defer browser-width logic until after mount.
FAQ
Is this always a bug in my Next.js app?
No. It can be caused by your code, but it can also be caused by external DOM mutation from browser extensions, translation tools, password managers, or auto-fill features. Always test in a clean browser profile first.
Should I ignore hydration warnings if the page seems to work?
No. Some warnings are harmless, but others indicate real UI inconsistencies that can cause broken interactivity or unexpected re-renders. You should identify whether the mismatch is intentional, external, or a real bug.
When should I use suppressHydrationWarning?
Only when a small piece of content is expected to differ between server and client and that difference is acceptable, such as a live timestamp. Do not use it to hide broader rendering problems across an entire component tree.
The core fix is simple: keep the first render deterministic, move browser-only logic to the client, and verify whether Chrome or an extension is mutating the DOM before hydration. Once the server HTML and client tree are aligned, the warning disappears.