FrontendPrep
Back to Next.js Questions
nextjsMedium

Next.js Client-Server Hydration Errors

Understand what Next.js hydration errors are, what causes them, and how to debug and resolve them in your React applications.

Next.js Client-Server Hydration Errors

One of the most common errors developers encounter when working with Next.js is the Hydration Mismatch:

"Error: Hydration failed because the initial UI does not match what was rendered on the server."

To solve and debug this error during frontend interviews, you must understand how React's Hydration process works.


1. What is Hydration?

In Server-Side Rendered (SSR) frameworks like Next.js, the server renders the page components into a static HTML string. The browser receives this HTML and displays it immediately, making the site load fast.

However, this raw HTML is not interactive yet. Hydration is the process where React runs on the client, matches the loaded HTML structure, and attaches event listeners (like onClick) to the DOM elements.


2. What Causes a Hydration Mismatch?

A hydration error occurs when the HTML generated by the server is different from the first HTML tree generated by React on the client.

The two most common causes are:

Cause A: Using Browser-Only APIs on Initial Render

If you use APIs like window, localStorage, or date objects directly in your rendering logic, the server and client will output different markup.

function BadComponent() {
  // Server: doesn't have 'window', returns empty or throws error
  // Client: has 'window', returns the innerWidth value
  const width = typeof window !== "undefined" ? window.innerWidth : 0;
 
  return <div>Screen width: {width}px</div>;
}

Cause B: Invalid HTML Structure Nesting

Browsers automatically correct malformed HTML. If your React component contains illegal nesting, the browser will restructure the DOM on load, making it differ from the raw HTML React expects.

A classic example is nesting a <div> inside a <p> tag:

function InvalidHtml() {
  // Browsers do not allow block elements (div) inside inline paragraphs (p).
  // The browser DOM parser splits the paragraph, breaking React's hydration tree.
  return (
    <p>
      <div>This will trigger a hydration error!</div>
    </p>
  );
}

3. How to Fix Hydration Errors

Solution 1: Use useEffect to Run Client-Only Logic

To prevent browser-only calculations from running on the server, move them inside a useEffect hook. useEffect only runs on the client after hydration is complete.

import { useState, useEffect } from "react";
 
function GoodComponent() {
  const [width, setWidth] = useState(0);
 
  useEffect(() => {
    // Runs only in the browser
    setWidth(window.innerWidth);
  }, []);
 
  return <div>Screen width: {width}px</div>;
}

Solution 2: Disable SSR for Specific Components

If a component must be rendered entirely on the client (like a theme switcher reading localStorage), load it dynamically with Next.js dynamic imports and disable Server-Side Rendering (ssr: false):

import dynamic from "next/dynamic";
 
// Loads ThemeToggle only on the client
const ThemeToggle = dynamic(() => import("./ThemeToggle"), {
  ssr: false,
});
 
export default function Layout() {
  return (
    <nav>
      <ThemeToggle />
    </nav>
  );
}

Solution 3: Use suppressHydrationWarning

For minor dynamic content (such as date stamps or user location values), you can add the suppressHydrationWarning attribute. This stops React from warning you about minor differences in attributes or text content.

function DateDisplay() {
  // Suppress warnings on the outer element
  return (
    <span suppressHydrationWarning>
      Current time: {new Date().toLocaleTimeString()}
    </span>
  );
}

Key Takeaways

  • Hydration is the step where React attaches event listeners to pre-rendered server HTML.
  • A hydration mismatch occurs when the server-rendered HTML doesn't match the client's first render tree.
  • Common culprits are invalid HTML structures (e.g. div inside p) or browser-only values (like window or localStorage) executed during rendering.
  • Fix hydration errors by moving browser-only code to useEffect, loading client components with ssr: false dynamic imports, or wrapping tags in suppressHydrationWarning.

Share this Resource

Help other developers level up by sharing this study guide.

More Technical Questions

Expand your mastery. Deep dive into other frontend interview challenges in this category.