Where does "use client" go? As low as possible
"use client" doesn't mark a component, it marks a boundary. Everything imported below it ships to the browser. Here's how to keep it in check.
In apps with Server Components (Next.js App Router) components are server components until you say otherwise. The "use client" directive doesn't say "this component is a client component" — it says "from here down, everything I import is part of the client bundle".
A common mistake
"use client"; // ❌ the whole page is now a client component
import { useState } from "react";
import { marked } from "marked"; // 40 kB shipped to the browser
export default function ProductPage({ product }) {
const [qty, setQty] = useState(1);
return (
<article>
<div dangerouslySetInnerHTML={{ __html: marked(product.description) }} />
<input type="number" value={qty} onChange={(e) => setQty(+e.target.value)} />
</article>
);
}Because of one input, an entire Markdown parser is sent to the browser.
Better: an interactive island
// ProductPage.tsx — Server Component, no directive
import { marked } from "marked"; // stays on the server
import { QuantityPicker } from "./QuantityPicker";
export default function ProductPage({ product }) {
return (
<article>
<div dangerouslySetInnerHTML={{ __html: marked(product.description) }} />
<QuantityPicker />
</article>
);
}// QuantityPicker.tsx
"use client";
import { useState } from "react";
export function QuantityPicker() {
const [qty, setQty] = useState(1);
return <input type="number" value={qty} onChange={(e) => setQty(+e.target.value)} />;
}Server children inside a client component
A client component can't import a server component, but it can receive one as children:
<Accordion> {/* "use client" — holds the open state */}
<ArticleBody /> {/* Server Component — rendered on the server */}
</Accordion>ArticleBody renders on the server and the client only receives the finished result.
Rules of thumb
- Put the directive on the leaves of the tree — buttons, inputs, animations.
- Props crossing the boundary must be serializable (no functions except Server Functions).
- Keep heavy libraries for formatting, Markdown or syntax highlighting on the server.