🚨 Next.js Hydration Error: Why Double "use client" Breaks Your Layout
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.jsxmust stay a server component if it hasmetadata.- Only child components (Navbar, Footer, Providers) should use
"use client". - If you use
"use client"in both thelayoutand its children → expect hydration hell. - Use a
ClientLayoutwrapper 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.





