Next.js
Server Components vs Client Components: Practical Rules of Thumb
When to use 'use client' and when to stay on the server—without the guesswork.

In the App Router, components are server by default. Use client components only where you need client-only behavior. These rules keep the boundary clear and the bundle small.
Stay server when you can
Server components run only on the server. They can async fetch, read env vars, and use server-only packages. They don’t ship JS for their tree (except when they render client components). Use server for: data fetching, static content, layout structure, and anything that doesn’t need useState, useEffect, or event handlers. Keep as much of the tree as possible on the server.
Use client for interactivity and browser APIs
Add "use client" at the top of a file when the component (or something it imports) uses hooks (useState, useEffect, useContext, etc.), event handlers (onClick, onChange), or browser APIs (window, document, localStorage). Client components run in the browser and ship their code. Push the boundary down: wrap only the interactive part in a client component and let the parent and siblings stay server.
// app/page.tsx (server)
import { ClientCounter } from "./ClientCounter";
export default function Page() {
return (
<div>
<p>Static intro from server.</p>
<ClientCounter />
</div>
);
}
// ClientCounter.tsx
"use client";
import { useState } from "react";
export function ClientCounter() {
const [n, setN] = useState(0);
return <button onClick={() => setN(n + 1)}>Count: {n}</button>;
}What you can’t do in server components
Server components cannot use hooks, event handlers, or browser APIs. They cannot import a client component directly and use it like a utility—they can only receive client components as children or pass them as props. They also cannot use context providers that rely on useState; put those in a client layout or wrapper. Don’t pass non-serializable data (functions, class instances) from server to client; pass serializable props only.
Passing children and composition
A server component can pass another server component as children to a client component. The server-rendered children are sent as part of the client component’s props. That’s how you get “client shell with server content inside”: the client component owns interactivity; the server fills the slots. Use this for layouts (client nav with server body) or wrappers (client modal with server-loaded content).
Summary
Default to server; add "use client" only for interactivity, hooks, or browser APIs. Keep the client boundary as low as possible, and use composition (server children into client components) to get the best of both. These rules keep your App Router apps fast and clear.