Server Components render on the server, can access backend resources directly, and don’t support client hooks/events. Client Components run in the browser, can use `useState/useEffect` and event handlers, but add JS to the bundle.
Advanced answer
Deep dive
In the App Router, components are **Server Components by default**. A Server Component renders on the server and sends a lightweight representation to the client (not its JS). This enables:
direct data access (DB/ORM/internal services) without exposing secrets,
smaller client bundles (fewer JS bytes),
better performance for mostly-static pages.
Client Components run in the browser. They’re used for interactivity (state, effects, event handlers) but increase the JS shipped to users.
Rules of thumb
Keep the UI tree server-first; introduce Client Components only at the leaves where you need interactivity.
Pass **serializable props** from server to client (no functions, DB connections, class instances).
Fetch data in Server Components when possible; keep client fetching for truly client-only data.
Example
// Server Component (default)
export default async function Page() {
const user = await getUser();
return <UserProfile user={user} />;
}
// Client Component
'use client'
function UserProfile({ user }: { user: { name: string } }) {
return <button onClick={() => alert(user.name)}>{user.name}</button>;
}
Common pitfalls
Making a high-level layout a Client Component (it forces huge parts of the tree to ship JS).