ReactSSRHydration

Fixing Hydration Failed Errors in React

Hydration errors happen when the HTML rendered on the server does not match the first render on the client. This article explains the most common causes and the practical fixes you can apply in React and Next.js projects.

2025-03-11·2 min·计算中...

Note: the imported Chinese source file available locally was truncated mid-article. This English version is reconstructed from the available source content and the original topic.

Fixing Hydration Failed Errors in React

React server-side rendering helps with page speed and SEO by sending pre-rendered HTML to the browser first. After that, React performs hydration to attach event handlers and turn that static HTML into a live, interactive React tree.

When the HTML generated on the server does not match the HTML produced by the client on the first render, React throws a Hydration Failed error.


What is a hydration error?

In a server-rendered React app, the server outputs HTML first, and the browser receives that HTML before JavaScript takes over. Hydration is the step where React reuses that markup instead of throwing it away and rendering everything from scratch.

If the server output and the initial client render differ, React cannot safely attach to the existing DOM. That mismatch triggers the hydration error.


Why does Hydration Failed happen?

1. Dynamic values produce different output

This is the most common cause. If the rendered markup depends on values such as:

  • Math.random()
  • Date.now()
  • new Date()
  • window
  • document
  • browser-only storage or APIs

then the server and client may generate different content.

Bad example:

export default function Page() {
  return <div>{Math.random()}</div>
}

The server renders one number, the browser renders another, and hydration fails.

Safer pattern:

'use client'

import { useEffect, useState } from 'react'

export default function Page() {
  const [value, setValue] = useState<number | null>(null)

  useEffect(() => {
    setValue(Math.random())
  }, [])

  return <div>{value ?? 'Loading...'}</div>
}
2. Async data is not consistent between server and client

If a component depends on data loaded asynchronously, but the server render and the client render do not use the same data snapshot, the resulting markup can differ.

Typical causes:

  • fetching data only on the client after the server already rendered placeholder content
  • conditionally rendering different states before data is ready
  • reading from a cache that is not synchronized between server and client

The fix is to make sure the initial render uses the same data on both sides, or to defer browser-only UI until after mount.

3. Browser-only APIs run too early

Code that accesses window, document, localStorage, sessionStorage, or media queries during render will break SSR assumptions.

Use one of these approaches instead:

  • gate the logic inside useEffect
  • render the browser-only part only on the client
  • in Next.js, use dynamic(..., { ssr: false }) for components that truly cannot render on the server
4. Invalid or unstable markup

Hydration can also fail when the DOM structure itself differs, for example:

  • invalid nested HTML
  • conditional branches that render different element trees
  • keys that change unexpectedly

If the element structure is unstable, React will not be able to hydrate it cleanly.


Practical checklist

When you see a hydration error, check these first:

  1. Remove Math.random(), Date.now(), and similar dynamic values from the render path.
  2. Move browser-only logic into useEffect.
  3. Make sure SSR and the initial client render use the same data.
  4. Check whether conditional rendering changes the DOM tree between server and client.
  5. Validate your HTML structure.

Summary

Hydration errors are not random. They almost always mean one thing: the first client render does not match the server-rendered HTML.

In practice, the most common fixes are:

  • avoid dynamic values during render
  • delay browser-only logic until after mount
  • keep the initial data consistent
  • make the rendered DOM structure stable

Once you treat hydration as a strict server/client consistency problem, these errors become much easier to debug.


Subscribe to FreeMac

Weekly picks: Mac productivity tips, free alternatives to paid software, and developer tools. Master your MacBook and save money.

← Back to articles