Medium🚨 Next.js Hydration Error: Why Double "use client" Breaks Your Layout | by Tofayel Islam | Medium
Sitemap
Tofayel Islam

Tofayel Islam

Frontend Developer

🚨 Next.js Hydration Error: Why Double "use client" Breaks Your Layout

2 min readOct 4, 2025

--

When working with the App Router in Next.js 13/14, it’s common to run into this nasty error:

A tree hydrated but some attributes of the server rendered HTML didn't match the client properties.

I ran into this exact problem while trying to integrate Lenis smooth scrolling in my project. The issue wasn’t with Lenis, fonts, or even my Navbar. The real culprit?

Get Tofayel Islam’s stories in your inbox

Join Medium for free to get updates from this writer.

👉 I was using "use client" in both the root layout.jsx and my child components.

❌ The Wrong Way

Here’s the mistake:

// src/app/layout.jsx
"use client"; // ❌ DON'T DO THIS

export const metadata = {
title: "My App",
};

export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<Navbar /> {/* Also has "use client" */}
{children}
</body>
</html>
);
}

Then inside Navbar.jsx:

"use client"; // Again ❌

This double client usage causes React to try rendering your layout as a client component, which conflicts with Next.js rules (layouts with metadata must stay server-side).
On top of that, it produces mismatches between server-rendered HTML and the hydrated client version → hydration errors.

âś… The Right Way

  • Keep RootLayout as a Server Component (default).
  • Use a ClientLayout wrapper if you need client-only logic (Lenis, Navbar, etc.).
  • Use "use client" only in components that really need it.
// src/app/layout.jsx (server component, no "use client")
import "./globals.css";
import { Poppins } from "next/font/google";
import ClientLayout from "@/components/layout/ClientLayout";

const poppins = Poppins({
variable: "--font-poppins",
subsets: ["latin"],
weight: ["400", "500", "600", "700"],
});

export const metadata = {
title: "My App",
};

export default function RootLayout({ children }) {
return (
<html lang="en" className={poppins.variable}>
<body>
<ClientLayout>{children}</ClientLayout>
</body>
</html>
);
}
Now ClientLayout handles the client-side stuff:
// src/components/layout/ClientLayout.jsx
"use client";

import { useEffect, useState } from "react";
import LenisProvider from "../providers/LenisProvider";
import Navbar from "./Navbar";
import Footer from "./Footer";

export default function ClientLayout({ children }) {
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);

if (!mounted) return null; // prevent hydration mismatch

return (
<LenisProvider>
<Navbar />
<main>{children}</main>
<Footer />
</LenisProvider>
);
}

🔑 Key Takeaways

  • layout.jsx must stay a server component if it has metadata.
  • Only child components (Navbar, Footer, Providers) should use "use client".
  • If you use "use client" in both the layout and its children → expect hydration hell.
  • Use a ClientLayout wrapper pattern to separate concerns.

If you see hydration errors in Next.js:
👉 Check if you’re using "use client" twice (in layout + components).
That’s the real enemy. Keep your layout.jsx clean, and push all interactive stuff into client-only wrappers.

--

--