Lesson 9 / 25

The Server-Client Boundary

What can cross, and what must not.

Serializable props, server-only secrets

Server Components can render Client Components and pass them props, but props crossing the boundary must be serializable (strings, numbers, plain objects, arrays, dates, promises; not functions, except Server Actions, and not class instances). Client Components cannot import Server Components directly, but can receive them as children. Keep secrets and server-only code out of client files; the server-only package makes importing a module from client code a build error.

Passing data and children across the boundary

A common pattern; not part of the built demo.

// app/dashboard/page.tsx  (Server Component)
import Tabs from "./Tabs";                // "use client" component
import { getStats } from "@/lib/stats";   // uses a database, imports "server-only"

export default async function Page() {
  const stats = await getStats();          // plain object: serializable
  return (
    <Tabs labels={["Overview", "Details"]}>
      <StatsTable stats={stats} />          {/* a Server Component passed as children */}
    </Tabs>
  );
}

Mark server-only modules

Add import "server-only" to modules with database access or secrets so they can never end up in a client bundle.

Quick check: Which prop cannot normally be passed from a Server to a Client Component?

  • A number array
  • A string
  • A regular function (other than a Server Action)
  • A plain object
Answer

A regular function (other than a Server Action) — Props must be serializable.