NextJS and React hydration problem on production

Marek Rozmus
3 min readMay 18, 2023

--

TL;DR: The problem was Cloudflare’s minification service.

Photo by Kym Ellis on Unsplash

In one of the projects I was working on lately I was using the static HTML export in Next.js. The way of building web app this way has it pros and cons but here I wanted to write about the problem that didn’t make any sense.

The problem

After deploying the build to production server and accessing some of the pages through the domain, the hydration errors like these appeared:

When following the links in from the console we get:

Text content does not match server-rendered HTML.

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

There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.

Unfortunately on production env we do not get any more information about what caused the problem, there is no information about which element caused the hydration that rebuilds the page.

There is a proposal in React’s repo for adding new functionality to debug hydration, but it looks like it have just vanished among other more urgent issues.

The (ideas for) solution

It could have been pretty obvious error but:

  • it was only on production, no problems on dev env, where actually more info about place of the problem could be available (mostly ;))
  • some of the pages with same structure had those errors and others didn’t — the only difference were the translation strings
  • the translations were not changing the page’s structure so why the hydration error appeared on one language but not on other?

A lot of fixes where tried like:

  • HTML structure mentioned in NextJS documentation
  • disabling the 3rd party scripts to narrow the root of the problem
  • replacing useLayoutEffect with useEffect
  • getting rid of React’s refs and useEffect for layout updates totally
  • cache busting to get latest content on the build time
  • even good old Markup Validation Service to check if pages’ structures were correct

The code improved :) but the problem persisted.

The idea

After whole day of “guessing” a new idea emerged — comparing the HTML pages. If there is some change happening in HTML structure then the questions are when and where.

After comparing the generated by the next export HTML pages with the ones that were placed on the server — no differences were found. To be sure the Postman application was used to get raw page from the server.

During that test one more thing was found — the published pages accessed directly didn’t have the hydration problems. That mean that something strange was happening on the way from the server to the client that enters the page through the domain.

After downloading the page again with Postman (but this time not from server directly but by entering the domain) and comparing to the original some small differences were found. So something had to change the page’s content on the way from server to end user.

The changes were very small and shouldn’t actually cause the hydration issue. The structure was the same but only some attributes were missing or names were changed, e.g.:

  • alt=”” was changed to alt
  • viewBox was changed to viewbox

But there were changes and it looks like in some cases it was enough for React to initiate hydration process.

After some investigation the root cause was found — Cloudflare’s minification service. It was minifying the pages on fly and caused all those issues.

When you actually know what to look for then everything is easy: https://github.com/vercel/next.js/issues/15876

After disabling that feature the pages content served through the domain were exactly the same as the ones generated by the next export command and the hydration problem disappeared.

--

--

Marek Rozmus
Marek Rozmus

Written by Marek Rozmus

Senior Frontend Engineer at GoStudent

No responses yet