Next.js 15 stable codemod has now caused my local font imports to produce hydration errors
Link to the code that reproduces this issue
https://github.com/tr1s/trisanity
To Reproduce
npm inpm run dev
These hydration errors will show this:
Then when you go to src/app/(frontend)/layout.tsx and remove the whole className block, the hydration errors go away:
return (
<html
lang="en"
className={`
${GTFAdieu.variable}
${GTFAdieu_Slanted.variable}
${GTFAdieu_Backslant.variable}
${Source_Sans_3.variable}
`}
>
<body>
<Nav />
<main role="main" id="main-content" tabIndex={-1}>
{children}
</main>
</body>
</html>
);
Next.js 15 has broken my local font importing.
Current vs. Expected behavior
Current behaviour: a working app with hydration errors Expected behaviour: a working app without hydration errors
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 24.0.0: Tue Sep 24 23:39:07 PDT 2024; root:xnu-11215.1.12~1/RELEASE_ARM64_T6000
Available memory (MB): 65536
Available CPU cores: 10
Binaries:
Node: 20.17.0
npm: 10.9.0
Yarn: N/A
pnpm: N/A
Relevant Packages:
next: 15.0.1 // Latest available version is detected (15.0.1).
eslint-config-next: 15.0.1
react: 19.0.0-rc-69d4b800-20241021
react-dom: 19.0.0-rc-69d4b800-20241021
typescript: 5.6.3
Next.js Config:
output: N/A
Which area(s) are affected? (Select all that apply)
Font (next/font)
Which stage(s) are affected? (Select all that apply)
next dev (local)
Additional context
I ran the Next.js 15 codemod and now I have hydration errors on my local font imports.
I tried with and without turbopack, same issues.
Here's my fonts.js that was working previously with Next 15 RC1:
/*
* Fonts.
* ------------------------------------------------------------------------------
*
*/
import localFont from 'next/font/local';
export const GTFAdieu = localFont({
variable: '--font-GTFAdieu',
src: [
{
path: '../../public/fonts/GTFAdieuTRIAL-Light.otf',
weight: '300',
style: 'normal',
},
{
path: '../../public/fonts/GTFAdieuTRIAL-Regular.otf',
weight: '400',
style: 'normal',
},
{
path: '../../public/fonts/GTFAdieuTRIAL-Bold.otf',
weight: '700',
style: 'normal',
},
],
});
export const GTFAdieu_Backslant = localFont({
variable: '--font-GTFAdieu-Backslant',
src: [
{
path: '../../public/fonts/GTFAdieuTRIAL-LightBackslant.otf',
weight: '300',
style: 'italic',
},
{
path: '../../public/fonts/GTFAdieuTRIAL-RegularBackslant.otf',
weight: '400',
style: 'italic',
},
{
path: '../../public/fonts/GTFAdieuTRIAL-BoldBackslant.otf',
weight: '700',
style: 'italic',
},
],
});
export const GTFAdieu_Slanted = localFont({
variable: '--font-GTFAdieu-Slanted',
src: [
{
path: '../../public/fonts/GTFAdieuTRIAL-RegularSlanted.otf',
weight: '400',
style: 'italic',
},
{
path: '../../public/fonts/GTFAdieuTRIAL-BoldSlanted.otf',
weight: '700',
style: 'italic',
},
],
});
export const Source_Sans_3 = localFont({
variable: '--font-Source-Sans-3',
src: [
{
path: '../../public/fonts/source-sans-3-v4-latin-regular.woff2',
weight: '400',
style: 'normal',
},
{
path: '../../public/fonts/source-sans-3-v4-latin-700.woff2',
weight: '700',
style: 'normal',
},
],
});
I am facing the same issue unfortunately
I am also getting hydration error on default npx create-next-app@latest
Interesting.
I'm surprised this wasn't caught and there's no comment about what's going on yet. Hopefully there's a fix in the next update!
actually this issues caused by browser extensions @tr1s
Ah okay, different issue for you then. My hydration errors are happening even on incognito with no browser extensions.
Update: The latest Next.js 15.0.2 did not resolve this issue.
same here, getting this error even on incognito mode, just created a latest nextjs project with turbopack
@tr1s I'm unable to run the reproduction repository, seems there's steps missing. During boot it ends up with:
Error: Failed to load configuration file "/project/workspace/sanity.config.ts":
Missing environment variable: NEXT_PUBLIC_SANITY_DATASET
at assertValue (/project/workspace/src/sanity/env.ts:16:11)
at Object.<anonymous> (/project/workspace/src/sanity/env.ts:4:24)
at Module._compile (/project/workspace/node_modules/esbuild-register/dist/node.js:2258:26)
at Object.newLoader (/project/workspace/node_modules/esbuild-register/dist/node.js:2262:9)
* The terminal process terminated with exit code: 1.
* Terminal will be reused by tasks, press any key to close it.
Can you narrow down the reproduction so that it can run with a default Next.js setup?
@qasimgit you have some browser extension modifying the page
@MasterProvider your comment is not helpful, please provide more details, likely same cause though, chrome extension.
same here, getting this error even on incognito mode, just created a latest nextjs project with turbopack
I had the same error, I tried incognito and I didn't get the error (I had all the extensions disabled), so I tried one by one to find out which one was giving me the error, I recommend that you check the browser extensions. In my case, 2 extensions caused the error.
And if I want to be more specific, the extension that gave me your same error was ColorZilla.
Can you narrow down the reproduction so that it can run with a default Next.js setup?
@timneutkens I've created a new repo, simplified it, and removed Sanity so you can run it. Here are the new steps:
git clone https://github.com/tr1s/trisanity-test.gitcd trisanity-testnpm inpm run dev
I've learned in doing this that the problem lies in the /src/app/layout.tsx. Once I remove that file the error goes away.
The /src/app/layout.tsx was left as is so it wouldn't mess up any Sanity Studio UI. Then I created a /src/app/(frontend)/layout.tsx where the layout for my frontend would live. This is where I imported my fonts. I was following along with this Sanity tutorial in which they did this.
For this setup when using a default layout and a nested (frontend) layout I was not getting any hydration errors until the Next.js RC2 and beyond. RC1 was working fine, and that's what this tutorial was based off.
So the two ways to remove this error is by 1. removing the base default layout.tsx or removing the fonts from the <html> tag in the nested (fronted) layout.tsx.
That's about all the context I can provide. Given that, do you know what may be going on?
I'm also facing this issue. I installed Next.js 15 using the command npx create-next-app@latest. However, when I try to run it, the browser shows an error. Interestingly, when I try in incognito mode, there’s no error.
I also installed it with Turbopack and used a src directory, and there’s no error there. I don’t know the reason, but it works for me.
@tr1s I'm unable to run the reproduction repository, seems there's steps missing. During boot it ends up with:
Error: Failed to load configuration file "/project/workspace/sanity.config.ts": Missing environment variable: NEXT_PUBLIC_SANITY_DATASET at assertValue (/project/workspace/src/sanity/env.ts:16:11) at Object.<anonymous> (/project/workspace/src/sanity/env.ts:4:24) at Module._compile (/project/workspace/node_modules/esbuild-register/dist/node.js:2258:26) at Object.newLoader (/project/workspace/node_modules/esbuild-register/dist/node.js:2262:9) * The terminal process terminated with exit code: 1. * Terminal will be reused by tasks, press any key to close it.Can you narrow down the reproduction so that it can run with a default Next.js setup?
@qasimgit you have some browser extension modifying the page
@MasterProvider your comment is not helpful, please provide more details, likely same cause though, chrome extension.
@timneutkens yes, it was colorzilla extension that was causing the issue, but now I am getting similar issue with the poppins font I have added.
here is my layout code
import type { Metadata } from "next";
import { Providers } from "./providers";
import { poppins } from "../fonts";
import "../globals.css";
export const metadata: Metadata = {
title: "Test",
description: "Test",
};
export default async function RootLayout({
children,
params,
}: {
children: React.ReactNode;
params: Promise<{
locale: string;
}>;
}) {
const awaitedParams = await params;
return (
<html lang={awaitedParams.locale} suppressHydrationWarning>
<body className={`${poppins.variable} antialiased`}>
<Providers locale={awaitedParams.locale}>{children}</Providers>
</body>
</html>
);
}
and here is my font code
import { Poppins } from "next/font/google";
export const poppins = Poppins({
subsets: ["latin"],
variable: "--font-poppins",
weight: ["400", "500", "600", "700"],
});
I have also added fonts in globals.css and tailwind.config.ts
body {
/* font-family: Arial, Helvetica, sans-serif; */
font-family: var(--font-poppins);
}
config
theme: {
fontFamily: {
poppins: ["var(--font-poppins)"],
},
@timneutkens I forgot to link to my new testing repo for simple steps to reproduce so I've now updated my previous comment and the original post with all the new and correct information.
i solve it by removing Urban VPN from extensions
So my hydration errors were fixed by removing the extra <html> and <body> tags in my nested layouts. I had to move my fonts to the main layout, and any components like <Nav> had to be moved to the nested layouts so it wouldn't show up in the Sanity Studio UI.
I'm assuming something changed in the latest update that made these appear as errors. Next.15 is supposed to have more clear hydration errors but in this case that doesn't appear to be true.
For anyone interested here's the PR that fixed it.
Something still doesn't feel right though because removing the html className fonts fixed the error too, which means when I had <html> and <body> inside my nested layouts there was no error. So, 🤷🏽♂️
I resolved it by adding same classname into html tag of both layouts
// app/layout.tsx
import { myFont } from './localFonts'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html
lang='en'
className={myFont.className}
>
{children}
</html>
)
}
=====================
// app/(frontend)/layout.tsx
import { myFont } from '../localFonts'
export default function Layout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
return (
<html
lang='en'
className={myFont.className}
>
<body>
...
</body>
</html>)
}
I solve it by disabling Trancy from the extensions
All I did was change
import localFont from "@next/font/local";
to
import localFont from "next/font/local";
and it's working fine now.
My problem now is that my icons now need me to explicitly color them according to current theme (dark or light)
turbopack
It's not turbopack issue
I've had a similar issue, sometimes I would get a hydration error, other times not, there was a race condition, it turned out to be a Chrome Extension issue, might make sense to check that (in my case it was Robots Exclusion Checker).
