HP1014 (head-mismatch) means the <title>, a <meta> tag or a stylesheet in
the document head changed while the page hydrated. Search engines, link
previews and the first paint use the server's values, so they never see the
final ones. Render the same head values on the server and the client, computed
from data the server has.
| Code | HP1014 |
|---|---|
| Name | head-mismatch |
| Default severity | Warning |
| Group | DOM mismatches |
| What it means | Metadata, stylesheets or scripts in <head> changed during hydration. |
What HP1014 (head-mismatch) means
hydration-proof compares the <head> right before hydration with the page after
the hydration commit's effects have run. It reports three things:
| Change | What the finding shows |
|---|---|
Hydration added a <title> with a new value | The server title and the added one |
A <meta> tag (by name, property, http-equiv or itemprop) got new content | The server content and the new one |
A stylesheet <link> from the server HTML was removed | Its href; the page can flash without styles |
Values are compared as sets, because React 19 adds a new <title> or <meta>
next to the server's instead of changing it. When that leaves two <title>
elements, the browser shows the first one, which is the server's.
Since the comparison runs after effects, a title set from an effect
(document.title = …) is reported as well.
Likely causes
- A title or description built from browser storage or another browser-only API.
- A locale or time formatted into the title.
- Data the client fetched again: different data.
How to fix it
- Render the same
<title>and<meta>tags on the server and the client, so search engines, link previews and the first paint show the final values. - Compute head values from data the server has (route params, cookies) instead of browser-only values.
A React 19 <title> that reads a name from storage:
"use client";
export function WelcomeTitle() {
const name =
typeof window === "undefined"
? "Guest"
: (localStorage.getItem("name") ?? "Guest");
return <title>{`Welcome, ${name}`}</title>;
}Build the title on the server instead. In the Next.js App Router, that is
generateMetadata, which can read cookies:
import { cookies } from "next/headers";
export async function generateMetadata() {
const name = (await cookies()).get("name")?.value ?? "Guest";
return { title: `Welcome, ${name}` };
}
export default function Page() {
return <h1>Welcome</h1>;
}When the difference is intentional
A title that changes on purpose after load, such as an unread count, is a
legitimate update. Add an ignore.issues rule with code: "HP1014", the route
and a reason; see ignoring findings.
Example
⚠ /welcome 890ms 1 warning
HP1014 Document head differs between server and client
head > title
attribute: title
server: "Welcome, Guest"
client: "Welcome, Sohail"
→ Render the same <title> and <meta> tags on the server and the client, so search engines, link previews and the first paint show the final values.