March 8, 2025-3min read

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

ImageBy SW Habitation
March 8, 2025

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:

Copy Code
1 2 3 export default function Home() { return <h1>{new Date().toLocaleTimeString()}</h1>; }

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()

Copy Code
1 2 3 4 5 6 7 8 9 10 11 import { useEffect, useState } from "react"; export default function Home() { const [time, setTime] = useState(""); useEffect(() => { setTime(new Date().toLocaleTimeString()); }, []); return <h1>{time}</h1>; }

✔ 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):

Copy Code
1 2 3 export default function Home() { return <h1>Screen Width: {window.innerWidth}</h1>; }

❌ Error: window is not defined on the server

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

Copy Code
1 2 3 4 5 6 7 8 9 10 11 import { useState, useEffect } from "react"; export default function Home() { const [width, setWidth] = useState(0); useEffect(() => { setWidth(window.innerWidth); }, []); return <h1>Screen Width: {width}</h1>; }

✔ 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):

Copy Code
1 2 3 export default function Home() { return <h1>Random Number: {Math.random()}</h1>; }

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

Copy Code
1 2 3 4 5 6 7 8 9 10 11 import { useState, useEffect } from "react"; export default function Home() { const [random, setRandom] = useState(null); useEffect(() => { setRandom(Math.random()); }, []); return <h1>Random Number: {random}</h1>; }

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:

Copy Code
1 2 3 export default function Home() { return <h1>{navigator.userAgent}</h1>; }

Error: navigator is only available on the client

Fix: Use useEffect() to update after hydration

Copy Code
1 2 3 4 5 6 7 8 9 10 11 import { useState, useEffect } from "react"; export default function Home() { const [userAgent, setUserAgent] = useState(""); useEffect(() => { setUserAgent(navigator.userAgent); }, []); return <h1>{userAgent}</h1>; }

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 }

Copy Code
1 2 3 4 5 6 7 import dynamic from "next/dynamic"; const Chart = dynamic(() => import("chart.js"), { ssr: false }); export default function Home() { return <Chart />; }

✔ 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()
Read More

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.

SW Habitation
Founder & CEO
Preview Pdf

Next blog that you can read...

March 3, 2025-6min read
How to Optimize or Improve Google Page Speed in Next.js?
ImageBy SW Habitation
February 25, 2025-4min read
Why Next.js Is Ideal for Headless CMS Integration ?
ImageBy SW Habitation
February 21, 2025-4min read
Flowbite: A Beginner’s Guide to UI Components for Tailwind CSS
ImageBy SW Habitation