React Server Components Explained in Plain English

Server Components render on the server, keep heavy code and secrets off the browser, and pair with Client Components for the interactive parts of a page.

7 min read

React Server Components are components that render on the server instead of in the browser. They produce the parts of a page that never need interactivity, and they can read a database or the filesystem directly while rendering. Only their finished output is sent to the browser, so their code and dependencies never ship to the client.

Stable in React 19

Server Components are stable in React 19, but they need a framework or bundler that implements them, such as the Next.js App Router. A plain Vite client-only app does not run Server Components.

Where Server Components run

A Server Component runs in an environment that is separate from both the browser and the server-side rendering pass. It can run once at build time on a CI server, or once per request on a web server. The right choice depends on whether the page data changes for each visitor.

Static content, like a changelog read from a file, can be rendered at build time and uploaded as plain HTML. Dynamic content, like a user's dashboard, should render per request so it always reflects fresh data.

Read data during render

Because a Server Component runs on the server, it can await a database query directly. The result becomes markup, and the query never shows up as a second client request.

App.jsxApp.jsx
import db from "./database";
 
async function Note({ id }) {
  const note = await db.notes.get(id);
  return (
    <div>
      <p>{note}</p>
    </div>
  );
}

The await happens while the component renders on the server. React suspends until the query resolves, then streams the finished paragraph to the page. The browser never receives the Note function or the database module, only the rendered text.

What Server Components cannot do

Server Components cannot hold state or respond to clicks. They are reduced to their output before the browser sees them, so nothing interactive can survive.

  • No event handlers. An onClick prop only works in a Client Component.
  • No state. useState and most other Hooks are unavailable.
  • No effects. There is no browser to synchronize with.

These limits are why a Server Component is usually paired with a Client Component for anything a user can touch.

Add interactivity with a Client Component

To make part of a page interactive, render a Client Component from a Server Component and pass it data or JSX. The Server Component stays the default, and the 'use client' marker only appears on the interactive piece.

App.jsxApp.jsx
import Expandable from "./Expandable";
 
async function Notes() {
  const notes = await db.notes.getAll();
  return (
    <div>
      {notes.map((note) => (
        <Expandable key={note.id}>
          <p>{note}</p>
        </Expandable>
      ))}
    </div>
  );
}

The Notes component reads a list and hands each item to Expandable as children. It passes the JSX for each note across the boundary, not the raw data object.

App.jsxApp.jsx
'use client';
 
import { useState } from "react";
 
export default function Expandable({ children }) {
  const [expanded, setExpanded] = useState(false);
  return (
    <div>
      <button onClick={() => setExpanded(!expanded)}>
        Toggle
      </button>
      {expanded && children}
    </div>
  );
}

Expandable holds a boolean in state and flips it when the button is clicked. The browser receives only this component's code, while the notes list arrives already rendered as output.

Server Components are not SSR

Server-side rendering turns a component tree into an HTML string on the server, then the client re-runs the same components to make them interactive. A Server Component goes further: its code never runs on the client at all. See Server Components vs Client Components for the full split of what runs where.

SSR and Server Components can be combined, which is what frameworks like Next.js do. The framework server-renders the output of Server Components and hydrates only the Client Components.

When to use Server Components

Reach for a Server Component when the work belongs on the server.

  • Use them for reading a database, files, or secrets that must stay off the client.
  • Use a Client Component for state, effects, or event handlers.
  • Pass data down with serializable props, or pass JSX as children.

The boundary marker is how the use client directive works. For mutations, reach for React Server Functions and Server Actions, which run on the server but stay callable from client code.

Rune AI

Rune AI

Key Insights

  • Server Components render on the server and ship only their output.
  • They can read a database or the filesystem directly during render.
  • They cannot use state, effects, or event handlers.
  • Compose them with Client Components for interactivity.
  • Server Components are not the same thing as server-side rendering.
RunePowered by Rune AI

Frequently Asked Questions

Do Server Components need a server running at request time?

Not always. They can render once at build time and ship as static HTML, or run per request on a web server for dynamic data.

Is there a directive that marks a Server Component?

No. Server Components are the default in a framework that supports them. The use server directive marks Server Functions, which is a different feature.

Conclusion

Server Components render on the server and send only their output to the browser, which keeps heavy code and secrets off the client. Compose them with Client Components for anything interactive.