Hydration failed

The HTML the server sent didn’t match what React rendered first in the browser, so React threw that part away and rebuilt it on the client.

Browser console and Next.js error overlay
Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used: - A server/client branch `if (typeof window !== 'undefined')`. - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called. - Date formatting in a user's locale which doesn't match the server. - External changing data without sending a snapshot of it along with the HTML. - Invalid HTML tag nesting. It can also happen if the client has a browser extension installed which messes with the HTML before React loaded. https://react.dev/link/hydration-mismatch

Also appears as

  • Hydration failed because the server rendered text didn't match the client. As a result this tree will be regenerated on the client.
  • A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up.
  • Minified React error #418; visit https://react.dev/errors/418?args[]=HTML&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
  • Hydration failed because the initial UI does not match what was rendered on the server.
  • Text content does not match server-rendered HTML.
  • There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.

Prompt to fix it

My app shows "Hydration failed because the server rendered HTML didn't match the client." Find the component that renders differently on the server and in the browser. Check for window, localStorage, or matchMedia reads during render, Date.now(), new Date(), Math.random(), dates formatted in the visitor’s locale, and invalid HTML nesting such as a div inside a p. Move browser-only values into useEffect with a first render that matches the server, and use useId for generated IDs. Don’t hide it with suppressHydrationWarning or turn off server rendering for the page. Tell me which mismatch you found.

Paste into Layerwise or any AI coding tool.

What it means

With server rendering, as in Next.js, the server sends finished HTML so the page appears fast. React then runs the same components in the browser and attaches to that HTML instead of building it again. That step is called hydration, and it only works if the first browser render produces exactly the markup the server sent.

When the two differ, React discards the server HTML for that part of the page and renders it again in the browser. The page usually still works, but it flickers, loses the speed benefit of server rendering, and in production logs a short Minified React error #418. In development, the error shows a diff: lines marked + are what the browser rendered, and lines marked - are what the server sent.

A common AI-written fix causes this error: wrapping code in if (typeof window !== 'undefined') during render. The server takes one branch and the browser takes the other, so the HTML can never match. Browser-only values belong in useEffect, which runs after hydration.

Common causes

  • A component reads window, localStorage, or the screen size while rendering, so the server and the browser render different output.
  • The markup includes new Date(), Date.now(), Math.random(), or a date formatted in the visitor’s locale or time zone.
  • The HTML nesting is invalid, such as a <div> inside a <p> or a link inside a link, and the browser rearranges it before React hydrates.
  • A browser extension, such as a password manager, translator, or grammar checker, changes the page before React loads.

How to fix it

  1. Read the diff in the error overlay or console to find the element and the value that differ.
  2. Move reads of window, localStorage, and matchMedia into useEffect, and render a neutral default until the effect runs.
  3. Render times and random values after mount, or format dates with a fixed timeZone so both sides agree. Use useId() for generated IDs.
  4. Fix invalid nesting: no <div> or <p> inside a <p>, no links inside links, and table rows inside a <tbody>.
  5. Reload in a private window with extensions off. If the error disappears, an extension caused it and your code is fine.

Example fix

'use client';

import { useEffect, useState } from 'react';

export function LocalTime({ iso }: { iso: string }) {
  // Empty on the server and on the first browser render, so both match.
  const [text, setText] = useState('');

  useEffect(() => {
    setText(new Date(iso).toLocaleString());
  }, [iso]);

  return <time dateTime={iso}>{text}</time>;
}
All errors
ReferenceError: window is not defined

ReferenceError: window is not defined

Code that only works in a browser ran on the server, where there is no window, document, or localStorage.

You're importing a module that depends on `useState` into a React Server Component module. This API is only available in Client Components. To fix, mark the file (or its parent) with the `"use client"` directive. Learn more: https://nextjs.org/docs/app/api-reference/directives/use-client

You’re importing a component that needs useState

A Next.js Server Component used a browser-side React feature like useState, which only works in files marked as Client Components.

Too many re-renders. React limits the number of renders to prevent an infinite loop.

Too many re-renders

A component changes its own state while it renders, so React renders it again and again until it stops the loop.

Each child in a list should have a unique "key" prop. Check the render method of `TodoList`. See https://react.dev/link/warning-keys for more information.

Each child in a list should have a unique "key" prop

A list rendered with map gave its items no stable ID, so React can’t tell which item is which when the list changes.

Build with an agent that checks its work

The Layerwise agent clicks through the live preview and reads the console, so it catches errors before you do.