Back to Blog Page
Frontend Development

Next.js Hydration Error: Hydration failed because the initial UI does not match what was rendered on the server [Fixed]

Next.js Hydration Error: Hydration failed because the initial UI does not match what was rendered on the server [Fixed]

Written by Kolade Chris | Oct 12, 2024 | #Next.js #React | 3 minute Read

Hydration errors in Next.js and React can be a real headache, as they can mess up how your site switches from static to interactive one. It’s one of the many bottlenecks of working with server-side rendering (SSR) in Next.js

Many claim they fix this error by passing the suppressHydrationWarning prop into the tag using the date or random number causing this error, but this does not apply to every situation. The safe thing to do is to dig deep and make sure there’s no mismatch between the server and the client.

Let’s first understand what hydration and hydration error are, and then we’ll look at how to fix the error.

What is Hydration?

In web development, particularly in a framework like Next.js, hydration refers to the process in which a JavaScript framework takes over a static HTML that was rendered by the server and attaches event handlers and other interactive behaviors to it.

Regarding the hydration error in Nex.js, it is the inconsistencies that occur when the JavaScript code running in the browser attempts to reuse the server-rendered HTML markup but finds differences it cannot resolve.

Next.js 14.2.2+ displays the error this way:

Next.js hydration error caused by date

What Causes a Hydration Error?

Differences in data rendered on the server and the client are the main course of the error. In other words, the error is an hydration mismatch. To be specific, on many occasions, hydration error is caused by the following in order:

  • Incorrect tag nesting. For example, p tag, wrapping a div tag or h1
  • the date object (new Date())
  • random numbers (Math.random())
  • third-party libraries or component libraries mismatching tags

The date object can cause issues because of timing mismatches. For example, if the server-rendered HTML includes a timestamp saying “Generated at 12:00 p.m.,” it may differ from what the client sees.

By the time the client loads and hydrates the content, it might be “12:01 p.m.,” causing the hydration process to detect a mismatch between the server-rendered output and the client-side JavaScript.

If you have two or more date objects in the same component, it can also cause the hydration error.

Random numbers can cause it the same reason the date object causes it.

How to Fix a Hydration Error in Next JS and React

In the case of tags, rearrange your tag nesting so a p tag does not wrap an img or a div. Here are nestings that can cause the error and how to fix them:

1
{
2
/*incorrect*/
3
}
4
<p>
5
<h1 className="text-5xl text-center mt-10">Home Page</h1>
6
</p>;
7
8
{
9
/*correct*/
10
}
11
<h1 className="text-5xl text-center mt-10">Home Page</h1>;
12
13
{
14
/*incorrect*/
15
}
16
<ul>
17
<p>
18
<li>First list</li>
19
</p>
20
</ul>;
21
22
{
23
/*correct */
24
}
25
<ul>
26
<li>First list</li>
27
</ul>;

In cases where the date object cause it, as you can see below, the solution is a bit different.

Next.js hydration error caused by date

You can see that the time on the server is 14:01:21 while the time on the client is 14:01:22. That’s a hydration mismatch between the client and the server.

This is the code that caused it:

1
'use client';
2
import { useEffect, useState } from 'react';
3
4
export default function Home() {
5
const [date, setDate] = useState(new Date());
6
7
useEffect(() => {
8
const interval = setInterval(() => {
9
setDate(new Date());
10
}, 1000);
11
12
return () => clearInterval(interval);
13
}, []);
14
15
return (
16
<div>
17
<h1 className="text-4xl mt-4 text-center">Current Date and Time</h1>
18
<p className="text-2xl text-center">{date.toString()}</p>
19
</div>
20
);
21
}

To fix the hydration mismatch between the client and the server in a situation where the date object causes it like this, you need to find a way to render the same value in the state the final value displayed, then conditionally render the date inside the JSX returned.

That means you should first get rid of the initial new Date() inside the state and set it to null:

1
'use client';
2
import { useEffect, useState } from 'react';
3
4
export default function Home() {
5
const [date, setDate] = useState(new Date());
6
const [date, setDate] = useState(null);
7
8
useEffect(() => {
9
const interval = setInterval(() => {
10
setDate(new Date());
11
}, 1000);
12
13
return () => clearInterval(interval);
14
}, []);
15
16
return (
17
<div>
18
<h1 className="text-4xl mt-4 text-center">Current Date and Time</h1>
19
<p className="text-2xl text-center">{date.toString()}</p>
20
</div>
21
);
22
}

The next thing is to conditionally render the date:

1
'use client';
2
import { useEffect, useState } from 'react';
3
4
export default function Home() {
5
const [date, setDate] = useState(null);
6
7
useEffect(() => {
8
const interval = setInterval(() => {
9
setDate(new Date());
10
}, 1000);
11
12
return () => clearInterval(interval);
13
}, []);
14
15
return (
16
<div>
17
<h1 className="text-4xl text-center mt-4">Current Date and Time</h1>
18
{date ? (
19
<p className="text-center text-2xl">{date.toString()}</p>
20
) : (
21
<p className="text-center text-2xl">Loading...</p>
22
)}
23
</div>
24
);
25
}

Now the client will display a Loading… text while the server does its job, then displays the date when everything is done.

Thank you for reading!