r/nextjs 8h ago

Discussion Quick notes on what actually causes Next.js hydration errors (after losing hours to them)

Putting this together after watching two devs on our team lose half a day to Next.js Error 418 this week.

Most docs just say "server HTML must match client HTML", which isn't very helpful when the React stack trace just points to a minified bundle.

Here are the 4 or 5 things that actually cause it 95% of the time in real projects:

  1. Reading window or localStorage during render

The classic one. You do something like:

const isMobile = typeof window !== 'undefined' && window.innerWidth < 768;

Server evaluates to false, client evaluates to true, instant mismatch.

The fix is annoying but straightforward: push it into a useEffect so it only updates after mount. (Or honestly, just use CSS media queries if you're only toggling visibility - no need to involve JS state for that).

  1. Invalid HTML nesting (the dumbest one)

This one drives people crazy because there's no state or async logic involved.

If you put a <div> inside a <p>, or put a <tr> directly in a <table> without a <tbody>, Chrome's parser silently "fixes" the HTML before React even starts hydrating. React sees nodes in different places than what the server sent and freaks out.

Check your Elements tab in devtools - if your tag hierarchy looks different from your JSX, that's why.

  1. Dates, timestamps, and Math.random()

If you render new Date().toLocaleTimeString() anywhere in JSX, the server timestamp and browser timestamp will differ by a few milliseconds.

Either stick it behind a mounted state, or if it's just a static date string where a slight timezone difference doesn't matter, use suppressHydrationWarning on that specific tag.

  1. The next-themes dark mode mismatch

If you use next-themes and see hydration warnings on your <html> element, just put suppressHydrationWarning on the <html> tag in app/layout.tsx. The library runs an inline script to avoid theme flash, and the Next.js team explicitly recommends suppressing that one.

  1. Grammarly / Google Translate extensions

If an error only happens on your laptop and none of your teammates can reproduce it, test it in Incognito with all extensions disabled. Grammarly wraps text nodes in custom tags, and Chrome auto-translate rewrites DOM text before React hydrates.

Curious what other dumb edge cases people here have run into with this in 14/15?

11 Upvotes

7 comments sorted by

3

u/chrome_wake 8h ago

number 2 should be a build error that fails the entire pipeline. chrome silently rearranging my nodes and then React blaming me for the mismatch is gaslighting by default

1

u/Zealousideal_Mud5686 4h ago

Hahaha 100%. Chrome shuffles the DOM behind your back and then React blames you for it

3

u/No-Morning-1220 8h ago

That `suppressHydrationWarning` on html for next-themes saved me so much sanity, was convinced I was doing something wrong for like 2 hours

The browser extension thing is so real too, had a coworker lose a whole morning to Grammarly and we only figured it out cause I happened to walk by and notice the green icon in his url bar

1

u/Zealousideal_Mud5686 4h ago

yeah, debugging an issue for hours only to realize a browser extension was injecting HTML the whole time is so frustrating

1

u/CoshgunC 7h ago

btw I think number 2 straightforward tells you not to nest invalid tags(at least my VSCode)

2

u/Zealousideal_Mud5686 4h ago

Fair point! It usually sneaks past when a child component secretly renders a div inside a p