QuestionsReact

Server Components vs Client Components

Server ComponentsHardReact

What are React Server Components (RSC), how do they differ from Client Components and from traditional SSR, and what are the rules for mixing them?

What it tests

Grasping the newest architectural shift: where a component runs and what that lets it do or forbids.

Approach & answer

Traditional SSR renders your whole app to an HTML string on the server, ships it, then *hydrates* — the same component code also runs on the client and all its JS is shipped. Server Components are a different axis: components that run *only* on the server and never ship their JS to the browser at all. Their rendered output is serialized and streamed to the client, which merges it into the tree. Benefits: zero bundle cost for server-only code, direct access to server resources (read a file, hit the database, use secrets) right inside the component with async/await, and less client JS overall. The constraints follow from 'this never runs in the browser': Server Components can't use state, effects, or event handlers (no useState/useEffect/onClick) and can't use browser-only APIs. Anything interactive must be a Client Component, marked with the `'use client'` directive at the top of the file, which opts that module (and its imports) into the client bundle. Composition rules: Server Components can import and render Client Components, but not vice versa — instead you pass Server Components *into* Client Components as children/props (a Client Component can render `{children}` that were produced on the server). Props crossing the boundary must be serializable (no functions). This is the model frameworks like Next.js App Router are built on; RSC and SSR are complementary, not competing.

Use this technique when

Static/data-heavy UI with server resource access and no interactivity → Server Component; anything with state/effects/handlers → Client Component ('use client').

Code

// app/page.jsx — Server Component (default, no directive). Runs on server only.
async function Page() {
  const posts = await db.query('SELECT * FROM posts'); // direct DB access, no API layer
  return <Feed posts={posts} />; // Feed can be a Client Component receiving serializable props
}

// Feed.jsx
'use client';                     // opts this module into the client bundle
export default function Feed({ posts }) {
  const [open, setOpen] = React.useState(false); // state is allowed here
  return <button onClick={() => setOpen(o => !o)}>{posts.length} posts</button>;
}

References