Stockio

How to Fix React Hydration Errors in Next.js

Diagnose React hydration mismatches by comparing server output with the first client render, then fix nondeterministic values, browser state, and invalid markup.

By Daniel Kim

React Developer ·

On this page

Hydration attaches React behavior to HTML that already exists. The first browser render must describe the same initial interface as the server render. A mismatch means those two descriptions disagree. Refreshing until the warning disappears does not repair the contract; it only changes the conditions that exposed it.

Compare the two initial snapshots

Begin with the exact component named in the warning and identify every input used during its first render. Look for time, randomness, locale, browser storage, cookies, request-specific data, and conditional environment checks. Initial agreement matters more than whether both renders eventually reach the same state.

Paste sanitized server and browser payloads into the JSON Formatter to compare their structures and values. Confirm that both renders received the same identifier and flags. Formatting is especially useful when one path silently omits a property that another path defaults differently.

Separate hydration mismatches from later state changes. Updating a greeting after an effect reads browser preferences can be legitimate. Rendering a different greeting immediately because window exists in the browser creates disagreement before hydration has completed. The distinction is about timing, not whether the final greeting is desirable.

Remove nondeterminism from render

Date.now and Math.random are common offenders. Calling either during server render and again during browser render produces independent values. Supply an initial value from the server when it is part of the document, or initialize browser-only behavior after hydration when that is genuinely required.

Locale formatting can also vary by environment. A date rendered with the server's default time zone may differ from the user's browser. Choose a consistent initial format and time zone, then optionally enhance the display after hydration. Deterministic rendering makes behavior testable as well as hydration-safe.

'use client';
import { useEffect, useState } from 'react';

export function LocalTime({ iso }: { iso: string }) {
const [display, setDisplay] = useState(iso);
useEffect(() => {
  setDisplay(new Intl.DateTimeFormat(undefined, {
    dateStyle: 'medium',
    timeStyle: 'short',
  }).format(new Date(iso)));
}, [iso]);
return <time dateTime={iso}>{display}</time>;
}

This component initially renders the same ISO value on both sides. It then enhances the presentation using the browser's locale. The input must still be a valid date string, and the layout should tolerate the display changing width. This is a deliberate two-phase presentation, not a reason to defer all page content.

Consult the React hydrateRoot reference for the expected contract. React's recovery behavior should not be treated as a substitute for correct markup; mismatches can undermine event attachment and force recovery work.

Check markup and browser parsing

The browser parses HTML before React hydrates it. Invalid nesting may be repaired into a different DOM tree than your JSX suggests. A paragraph containing block-level structures or a nested interactive element can therefore create a mismatch even when the source looks identical on both sides.

Inspect the actual DOM and compare it with the response source. Parser repair is easy to miss when inspecting JSX alone. Look at table structures, paragraphs, buttons, anchors, and third-party components that choose their own wrapper elements. A design-system component named Text might render a paragraph rather than a neutral span.

Use the MDN HTML reference to verify content models instead of rearranging elements until the warning disappears. Prefer semantic corrections that preserve interaction behavior. Replacing everything with div elements may hide one nesting issue while weakening the document's structure.

Also test without extensions that modify the page. Password managers, translation tools, and injected browser UI can change markup before hydration. That does not mean every mismatch should be blamed on extensions; first reproduce in a clean profile and compare the result with the normal environment.

Handle browser-only state deliberately

Reading localStorage during render can make the client start from a different state than the server. For a theme or preference, decide whether the server can know the value through a cookie. If not, choose a stable initial state and an explicit enhancement strategy that accepts any visual transition.

Do not use typeof window as a blanket branch inside render to produce unrelated initial trees. The check avoids a reference error but can create the mismatch itself. Browser availability and first-render consistency are separate requirements.

For components that genuinely cannot render meaningfully on the server, use the framework's documented client-only loading pattern at an appropriate boundary. Keep that exception narrow. Turning the whole route into client-only rendering to silence one widget loses server-rendering benefits and makes diagnosis harder.

The Next.js hydration error guide explains supported escape hatches. suppressHydrationWarning is intended for limited unavoidable differences, not a general repair switch. It does not establish a correct data contract, sanitize markup, or guarantee React will patch every mismatch the way you expect.

Reproduce the conditions that caused it

Test a hard refresh, not only client-side navigation. Hydration is particularly visible on initial document loads, while later transitions can follow a different path. Try multiple locales and time zones when dates or numbers are involved. Include an authenticated and signed-out request if personalization affects the first render.

Capture server props and the first client props in a minimal reproduction. Remove unrelated widgets until the warning disappears, then restore them one at a time. Small reproductions expose hidden environment reads and wrapper changes faster than changing a global rendering setting.

Add a regression test for the actual source of nondeterminism. Fix the clock for time-sensitive output, provide a stable locale, and supply the same initial snapshot to server and browser rendering. A snapshot test of the final hydrated UI alone can miss the initial disagreement entirely.

The React collection and development collection contain related implementation patterns. Keep your own hydration checklist focused on concrete evidence: incoming data, parsed DOM, first-render values, and environment differences. Evidence before suppression prevents an intermittent warning from becoming an undocumented production assumption.

Finally, confirm that the fix preserves useful initial content. A page that renders nothing until an effect runs may avoid disagreement, but it can also obscure the original rendering design problem. Prefer shared inputs and deterministic output whenever possible.

Key takeaways

  • Compare server output with the first browser render, not merely the final UI.
  • Stabilize time, randomness, locale, initial data, and browser preference handling.
  • Check parsed HTML and third-party wrappers before using narrowly scoped escape hatches.
Featured sponsor

Reach designers & developers at work

Put your product next to the tools people use every day. One sponsor per placement, no tracking pixels.

Become a sponsor

Keep reading

Related articles

More in JavaScript & Frameworks
JavaScript & Frameworks

10 Best JavaScript Charting Libraries

Compare ten JavaScript chart libraries for dashboards, reports, and interactive data stories. See where each excels, what it costs, and how to choose based on your app and team.

Includes: JSON formatterSofia MarchettiSofia Marchetti
JavaScript & Frameworks

8 Best React State Management Libraries

Find a React state approach that fits your app, from built-in hooks to dedicated stores, with clear trade-offs around data flow, debugging, async work, and learning effort.

Includes: JSON formatterSofia MarchettiSofia Marchetti
JavaScript & Frameworks

12 Best and Most Popular JavaScript Libraries

Compare twelve widely used JavaScript libraries for interfaces, data, testing, and everyday development, with clear strengths, trade-offs, and advice for choosing only what your project needs.

Includes: JSON formatterSofia MarchettiSofia Marchetti
JavaScript & Frameworks

localStorage vs sessionStorage vs IndexedDB Compared

Choose browser storage by data lifetime, size and access pattern. Compare synchronous Web Storage with IndexedDB transactions, migrations, quotas and failure handling.

Includes: JSON formatterSofia MarchettiSofia Marchetti
JavaScript & Frameworks

React Server Components Explained for Developers

Learn what React Server Components execute, what crosses the client boundary, and how to structure data access, interactive widgets, and mutations without leaking private data.

Includes: JSON formatterDaniel KimDaniel Kim
JavaScript & Frameworks

useMemo vs useCallback vs React.memo: Fewer Rerenders

Learn when React memoization helps, how prop identity affects rerenders, and why profiling and state placement should come before useMemo and useCallback.

Includes: JSON formatterDaniel KimDaniel Kim