DEV Community

swhabitation
swhabitation

Posted on • Originally published at swhabitation.com

How to Fix Hydration Errors in Next.js ? A Complete Guide

Have you ever seen this error in your Next.js app?

Hydration failed because the server-rendered HTML did not match the client....

What is Hydration ?

Hydration is the process where static HTML becomes interactive by adding javascript to it.

When a web page is rendered on the server it loses its interactivity and event handles before getting to the client.

Now react come into the picture. React adds the interactivity and event handlers that were lost when the HTML was server-side rendered.

Lets understand in some simple terms, This is a hydration error, and it happens when the server renders one version of your page, but the browser (client) renders something different.

It’s one of the most common issues in Next.js, especially if you're using dynamic content, third-party scripts, or certain hooks like useEffect.

In this blog, we’ll cover,

  • What is Hydration in Next.js?
  • What causes hydration errors in Next.js ?
  • How to debug and fix ?
  • Best practices to avoid.

What is Hydration in Next.js?

Hydration is the process where react attaches interactivity to a pre-rendered HTML page.

  • Server-side rendering (SSR): The server sends fully rendered HTML to the browser.
  • Client-side hydration: React reuses this HTML but adds event listeners and dynamic content.

In short, If what the server rendered doesn’t match what the client renders, you get a hydration error.

Common Causes of Hydration Errors & Fixes

1. Mismatched Content Between Server & Client

Problem: If the server and client render different content, React will throw a hydration error. Example:

export default function Home() {
  return <h1>{new Date().toLocaleTimeString()}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

The server renders a fixed timestamp when it builds the page.

The client re-renders with the current time, causing a mismatch.

Fix: Wrap dynamic content inside useEffect()

import { useEffect, useState } from "react";

export default function Home() {
  const [time, setTime] = useState("");

  useEffect(() => {
    setTime(new Date().toLocaleTimeString());
  }, []);

  return <h1>{time}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

✔ Now, the server renders a placeholder (""), and the client updates the time after hydration.

2. Using window, document, or localStorage in SSR

Problem: Server-side rendering (SSR) happens before the browser loads, so window, document, and localStorage don’t exist.

Example (Incorrect Usage):

export default function Home() {
  return <h1>Screen Width: {window.innerWidth}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

❌ Error: window is not defined on the server

✅ Fix: Use useEffect() to access window on the client side.

import { useState, useEffect } from "react";

export default function Home() {
  const [width, setWidth] = useState(0);

  useEffect(() => {
    setWidth(window.innerWidth);
  }, []);

  return <h1>Screen Width: {width}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

✔ Now, the server renders an empty value (0), and the client updates it after hydration.

3. Using Random or Time-Based Values in Server Components

Problem: Values like Math.random() or Date.now() generate different results on the server and client, causing a mismatch.

Example (Incorrect Usage):

export default function Home() {
  return <h1>Random Number: {Math.random()}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

✅ Fix: Generate the value only on the client side using useState & useEffect.

import { useState, useEffect } from "react";

export default function Home() {
  const [random, setRandom] = useState(null);

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

  return <h1>Random Number: {random}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

4. Conditional Rendering Based on Client Data

Problem: If a component renders differently on the server and client, React will throw a hydration error.

Example:

export default function Home() {
  return <h1>{navigator.userAgent}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

❌ Error: navigator is only available on the client

✅ Fix: Use useEffect() to update after hydration

import { useState, useEffect } from "react";

export default function Home() {
  const [userAgent, setUserAgent] = useState("");

  useEffect(() => {
    setUserAgent(navigator.userAgent);
  }, []);

  return <h1>{userAgent}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

5. Third-Party Scripts Running on the Server

Problem: Some third-party libraries (e.g., charts, ads, analytics) try to run on the server but rely on the browser.

✅ Fix: Use dynamic() with { ssr: false }

import dynamic from "next/dynamic";

const Chart = dynamic(() => import("chart.js"), { ssr: false });

export default function Home() {
  return <Chart />;
}
Enter fullscreen mode Exit fullscreen mode

✔ Now, the component only loads in the browser, preventing hydration issues.

Best Practices to Avoid Hydration Errors

  • Always use useEffect() for client-specific code (e.g., window, document, localStorage)
  • Use placeholders or default values for SSR-rendered content
  • Wrap third-party libraries with dynamic() and ssr: false
  • Avoid using random values (Math.random(), Date.now()) directly in server-rendered components
  • Use useState() for dynamic values and update them in useEffect()

Conclusion

Hydration errors in Next.js happen when the server and client render different content. They can be frustrating, but fixing them is simple:

✅ Use useEffect() for client-only code
✅ Lazy load third-party libraries using dynamic()
✅ Avoid dynamic content in server-rendered components

Following these best practices will help you avoid hydration errors and build a smoother, faster Next.js app.

Top comments (2)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.