Skip to content
managing-server-vs-client-boundaries logo

Server vs Client Component Boundaries

managing-server-vs-client-boundaries

Teaches when to use Server Components vs Client Components in React 19, including the 'use client' directive and boundary patterns. Use when architecting components, choosing component types, or working with Server Components.

SKILL.md

Full skill instructions

Server vs Client Component Boundaries

Role: Choose between Server and Client Components effectively and manage boundaries between them.

When to Activate

  • User mentions Server Components, Client Components, or 'use client'
  • Architecting component hierarchy
  • Accessing server-only or client-only APIs
  • Working with React Server Components frameworks (Next.js, Remix)
  • Errors about hooks or browser APIs in Server Components

Component Comparison

FeatureServer ComponentClient Component
DirectiveNone (default)'use client'
Hooks; Event handlers; Browser APIs❌✅
Async/​await (top-level)✅⚠️ Limited
Database/​server APIs✅ Direct❌ Use Server Actions
Import Server Components✅❌ Pass as children
Bundle impact📦 Zero📦 Sent to client
Bundle reduction20%-90%—

Key Decision: Needs interactivity/​hooks/​browser APIs → Client Component; static/​server-only data → Server Component

Quick Checklist

Choose Client Component if: needs hooks, event handlers, browser APIs, or state management.

Choose Server Component if: purely presentational, fetches server data, accesses databases/​server APIs.

Implementing Components

Step 1: Add 'use client' at file top (Client Components only)

'use client';

import { useState } from 'react';

export function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>Count: {count}</​button>;
}

Step 2: Compose Server + Client

Server Components import Client Components; pass Server Components as children to avoid circular imports:

// Server Component: Can fetch data, import CC
import { Counter } from './​Counter';

async function Page() {
  const data = await db.getData();
  return (
    <div>
      <h1>{data.title}</​h1>
      <Counter />
    </​div>
  );
}

// ❌ WRONG: Client Component importing Server Component
('use client');
import ServerComponent from './​ServerComponent'; // ERROR

// ✅ RIGHT: Pass Server Component as children
<ClientWrapper>
  <ServerComponent />
</​ClientWrapper>;

Common Patterns

Interactivity at leaf nodes: Server Component fetches data, passes to Client Component for interaction

async function ProductPage({ id }) {
  const product = await db.products.find(id);
  return (
    <>
      <ProductDetails product={product} />
      <AddToCartButton productId={id} />
    </>
  );
}

Server data in Client Component: Pass as props (serialize data)

async function ServerComponent() {
  const data = await fetchData();
  return <ClientComponent data={data} />;
}

Server logic from Client: Use Server Actions

async function ServerComponent() {
  async function serverAction() {
    'use server';
    await db.update(...);
  }
  return <ClientForm action

={serverAction} />;
}

Example: Product Page with Cart

// Server Component
import { AddToCart } from './​AddToCart';
import { Reviews } from './​Reviews';

async function ProductPage({ productId }) {
  const product = await db.products.find(productId);
  const reviews = await db.reviews.findByProduct(productId);

  return (
    <main>
      <img src={product.image} alt={product.name} />
      <section>
        <h1>{product.name}</​h1>
        <p>{product.description}</​p>
        <p>${product.price}</​p>
        <AddToCart productId={productId} />
      </​section>
      <Reviews reviews={reviews} />
    </​main>
  );
}

// Client Component
('use client');
import { useState } from 'react';

export function AddToCart({ productId }) {
  const [adding, setAdding] = useState(false);

  async function handleAdd() {
    setAdding(true);
    await fetch('/​api/​cart', {
      method: 'POST',
      body: JSON.stringify({ productId }),
    });
    setAdding(false);
  }

  return (
    <button onClick={handleAdd} disabled={adding}>
      {adding ? 'Adding...' : 'Add to Cart'}
    </​button>
  );
}

// Server Component with real-time Client
async function Dashboard() {
  const stats = await db.stats.getLatest();
  return (
    <>
      <DashboardStats stats={stats} />
      <LiveMetrics />
    </>
  );
}

// Client Component with WebSocket
('use client');
import { useEffect, useState } from 'react';

export function LiveMetrics() {
  const [metrics, setMetrics] = useState(null);

  useEffect(() => {
    const ws = new WebSocket('/​api/​metrics');
    ws.onmessage = (event) => setMetrics(JSON.parse(event.data));
    return () => ws.close();
  }, []);

  return metrics ? <div>Active Users: {metrics.activeUsers}</​div> : <div>Connecting...</​div>;
}

// Server Component with Server Action
async function ContactPage() {
  async function submitContact(formData) {
    'use server';
    await db.contacts.create({
      email: formData.get('email'),
      message: formData.get('message'),
    });
  }

  return (
    <form action={submitContact}>
      <input name="email" type="email" />
      <textarea name="message" />
      <button type="submit">Send</​button>
    </​form>
  );
}

Requirements

MUST: 'use client' at file top for Client Components; before any imports; serialize props (Server → Client); use Server Actions for server-side logic from Client

SHOULD: Keep most components as Server Components (smaller bundle); place 'use client' at leaf nodes (smallest boundary); use Server Components for data fetching; use Client Components only for interactivity

NEVER: Import Server Components into Client Components; use hooks in Server Components; access browser APIs in Server Components; pass non-serializable props (functions, classes, symbols); om

it 'use client' directive

Validation Checklist

  1. Component Types: Client Components have 'use client' at top; Server Components have no directive; no hooks/​event handlers in Server Components
  2. Data Flow: Server → Client props are serializable; Client → Server uses Server Actions; no Server Components imported in Client
  3. Functionality: Server Components fetch data correctly; Client Components handle interaction; no hydration mismatches; no runtime errors about hooks/​browser APIs
  4. Bundle: Only necessary components are Client Components; most stay on server; JavaScript minimized

References

  • Server Components: research/​react-19-comprehensive.md (lines 71-82)
  • Server Actions: forms/​skills/​server-actions/​SKILL.md
  • Component Composition: component-composition/​SKILL.md

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View