Only add "use client" when a component needs hooks, event handlers, or browser APIs. Every unnecessary "use client" directive ships the component and all its dependencies to the browser as additional JavaScript — slowing down page loads, increasing bandwidth costs, and degrading the experience for users on slow connections or low-powered devices.
Every "use client" directive adds the component and all its dependencies to the client JavaScript bundle. Unnecessary client components increase page load time, Time to Interactive (TTI), and bandwidth usage. On large applications this can add hundreds of kilobytes of avoidable JavaScript.
BeforeMerge scans your pull requests against this rule and 3+ others. Get actionable feedback before code ships.
In Next.js App Router, components are Server Components by default. Adding "use client" at the top of a file opts that component (and its entire import subtree) into the client bundle. This means:
Unnecessary "use client" directives are the leading cause of bloated Next.js bundles.
Only add "use client" when the component genuinely needs one of:
useState, useEffect, useRef, etc.)onClick, onChange, onSubmit, etc.)window, document, localStorage, etc.)If the component only renders data, use a Server Component.
"use client"; // Unnecessary!
import { formatDate } from "@/lib/utils";
export function ArticleCard({ title, date, excerpt }: ArticleCardProps) {
return (
<div className="rounded-lg border p-4">
<h2>{title}</h2>
<time>{formatDate(date)}</time>
<p>{excerpt}</p>
</div>
);
}This component has no hooks, no event handlers, and no browser APIs. It should be a Server Component.
// No "use client" — this is a Server Component
import { formatDate } from "@/lib/utils";
export function ArticleCard({ title, date, excerpt }: ArticleCardProps) {
return (
<div className="rounded-lg border p-4">
<h2>{title}</h2>
<time>{formatDate(date)}</time>
<p>{excerpt}</p>
</div>
);
}When you need interactivity for a small part of a larger component, extract only the interactive part into a client component:
// article-page.tsx — Server Component
import { LikeButton } from "./like-button"; // Client Component
export async function ArticlePage({ id }: { id: string }) {
const article = await getArticle(id); // Server-side data fetch
return (
<article>
<h1>{article.title}</h1>
<p>{article.content}</p>
<LikeButton articleId={id} /> {/* Only this part is client-side */}
</article>
);
}// like-button.tsx — Client Component (needs onClick + useState)
"use client";
import { useState } from "react";
export function LikeButton({ articleId }: { articleId: string }) {
const [liked, setLiked] = useState(false);
return (
<button onClick={() => setLiked(!liked)}>
{liked ? "Unlike" : "Like"}
</button>
);
}Review every "use client" file and ask:
"use client"."use client" is justified.grep -rn '"use client"' app/ components/ --include="*.tsx" --include="*.ts""use client" from components that don't need itnext/bundle-analyzer to measure the impact