Server Components are the foundation the entire App Router is built on: components that render on the server and send only HTML (plus minimal instructions) to the browser, with zero of their own JavaScript shipped to the client. This lesson explains how and why they work.
What Makes a Component a Server Component?
In the App Router, every component is a Server Component unless its file starts with a "use client" directive. Server Components run exclusively on the server (or at build time), meaning their code — including any imports, like a database client or an API secret key — never gets bundled into the JavaScript sent to the browser.
Because they run on the server, Server Components can be async functions, letting you await a database query or fetch() call directly inside the component body, with the resulting data already baked into the rendered HTML by the time it reaches the browser.
// app/products/page.tsx — a Server Component (no directive needed)
import { db } from "@/lib/db";
export default async function ProductsPage() {
const products = await db.product.findMany();
return (
<ul>
{products.map((p) => (
<li key={p.id}>{p.name}</li>
))}
</ul>
);
}
The db client and every line of this component's logic run only on the server; the browser receives just the resulting <ul> HTML.
Server Component Rules
// Allowed in a Server Component:
async function Component() { /* await db calls, fetch, etc. */ }
// NOT allowed in a Server Component:
// useState, useEffect, onClick, or any browser-only API
No directive at the top of the file means a component is a Server Component (the default).
Server Components can be async and can directly access server-only resources.
Server Components cannot use React hooks like useState/useEffect, or event handlers like onClick.
Server Components can render Client Components, passing them serializable data as props.
Server Components Cheat Sheet
What Server Components can and can't do.
Capability
Server Component
Can be async
Yes
Can use useState / useEffect
No
Can use event handlers (onClick)
No
Ships JavaScript to the browser
No (its own code, at least)
Can access secrets/env vars safely
Yes
Can query a database directly
Yes
Can render Client Components
Yes, as children
Server Components vs. Traditional SSR
Traditional server-side rendering (like the Pages Router's getServerSideProps) still ships the entire page's component code as JavaScript to the browser for hydration, even though the initial HTML was rendered on the server. Server Components go further: their code never ships to the browser at all, because they never need to run there again — there's no hydration step for pure Server Component output.
Aspect
Traditional SSR
Server Components
Initial HTML from the server
Yes
Yes
Component JS shipped to browser
Yes (for hydration)
No
Re-renders in the browser
Yes
Never (unless it's a Client Component)
Composing Server and Client Components
A Server Component can import and render a Client Component directly. The reverse — a Client Component importing a Server Component directly — is not allowed, though a Client Component can still receive a pre-rendered Server Component as a children prop, which is the recommended pattern.
Server Component → renders → Client Component: always allowed.
Client Component → imports → Server Component: not allowed directly.
Client Component → receives a Server Component via children/props: allowed and common.
Common Mistakes
Adding "use client" to a component that only fetches and displays data, unnecessarily shipping it to the browser.
Trying to import a Server Component directly inside a Client Component's file.
Passing non-serializable values (like a function or a class instance) from a Server Component to a Client Component as props.
Assuming Server Components re-render in the browser on state changes elsewhere in the app — they don't re-run client-side at all.
Key Takeaways
Server Components are the App Router default; no directive is needed to opt in.
They run only on the server and can be async, enabling direct data fetching.
They cannot use hooks or event handlers, since they never execute in the browser.
Their own code is never shipped to the browser, reducing client-side JavaScript.
Server Components can render Client Components, but not vice versa (directly).
Pro Tip
When designing a new feature, sketch which parts genuinely need interactivity first, and default everything else to Server Components — most real-world UI (data display, formatting, layout) needs no client-side JavaScript at all.
You now understand Server Components deeply. Next, learn about Client Components — the opt-in counterpart for interactivity.