---
title: "Fix Next.js “Text content does not match server-rendered HTML” React hydration error"
description: "Learn how to fix the React hydration error “Text content does not match server-rendered HTML” so you can personalize &#38; transform HTML in your Next.js apps."
source: "https://www.netlify.com/blog/fix-next-js-react-hydration-error/"
last_updated: "2026-07-14T18:29:05.000Z"
---
If you’ve ever tried to personalize a Next.js app, you may have run into this error:

```
Unhandled Runtime ErrorError: Text content does not match server-rendered HTML.
See more info here: https://nextjs.org/docs/messages/react-hydration-error
```

This happens when the rendered HTML (built using SSR, ISR, static export, or other Next.js rendering techniques) is updated, but the React code that hydrates after the page loads is not.

React hydration errors are frustrating. Many personalization approaches don’t work because they don’t account for the way Next.js SSR builds each page twice — the mismatch between the server-rendered and client-rendered pages is both confusing and hard to fix.

In this step-by-step tutorial, we’ll learn how we can use [Next.js Advanced Middleware on Netlify](https://docs.netlify.com/integrations/frameworks/next-js/middleware/) to transform a Next.js app to allow for personalization, split testing, and A/B testing without needing complex workarounds (such as creating two different versions of the same page and setting up redirects or rewrites between them).

If you want to skip ahead into the result, follow these links:

-   [See the demo](https://update-content-nextjs-hydration.netlify.app/)
-   or [jump straight into the source code](https://github.com/jlengstorf/update-content-nextjs-hydration).

## Why React hydration errors happen in Next.js

In a Next.js app, pages get rendered twice:

1.  During the _server_ phase using SSR, ISR, or a static export. This takes the React components and turns them into rendered HTML, which works without JavaScript enabled.
2.  During the _client_ phase, called “hydration”, where the browser uses JavaScript to mount the app as React code. This turns the static HTML back into an active JavaScript application, known as a “single-page app” (SPA).

React requires that the server-rendered markup exactly matches the React SPA markup.

### Transforming React code at the edge is hard due to hydration

The act of transforming HTML at the edge is fairly straightforward: set up an Edge Function, use a tool like HTMLRewriter, and you’re off to the races!

But with React hydration, you have to transform _both_ the rendered HTML _and_ the JavaScript that renders the SPA — this tends to be prohibitively complex in many cases.

## How to transform Next.js pages and avoid React hydration errors

The common workaround for modifying Next.js pages while avoiding hydration errors is pretty unwieldy. The guidance is to create two slightly modified versions of the same page and use a rewrite to change what’s displayed.

This is fine for a split testing scenario, but doesn’t handle personalization and also creates painful maintenance headaches.

To do true personalization, we need to customize what’s displayed _per user_, and that currently requires a full server-rendering strategy.

In this tutorial, we’ll look at a technique that allows personalization _without_ creating multiple versions of the page _or_ needing to resort to full SSR for personalization.

### 1\. Create a Next.js app

If you don’t have a Next.js app already, create one with the following commands:

```
# generate a new Next.js appnpx create-next-app@latest
# move into the new app (use your own app’s folder name!)cd ./my-nextjs-app
```

> **Note:** you can skip this step if you already have a Next.js app created.

### 2\. Set up a Next.js page

First, create a page in your Next.js app that you’d like to transform.

For this example, update the contents of `pages/index.js` in your app to the following:

```
import Head from 'next/head';import styles from '../styles/Home.module.css';
export async function getStaticProps() {  return {    props: {      heading: 'The best headlines around!',      details: 'This response is static.',    },  };}
export default function Home({ heading, details }) {  return (    <div className={styles.container}>      <Head>        <title id="title">{heading}</title>        <link rel="icon" href="/favicon.ico" />      </Head>
      <main>        <h1 id="heading">{heading}</h1>
        <p>          Update and replace content in Next.js and avoid React hydration          errors. <span className="details">{details}</span>        </p>      </main>    </div>  );}
```