--- name: managing-server-vs-client-boundaries description: 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. allowed-tools: Read, Write, Edit, Glob, Grep version: 1.0.0 --- # 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 | Feature | Server Component | Client Component | | ----------------------------------- | ---------------- | --------------------- | | Directive | None (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 reduction | 20%-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) ```javascript 'use client'; import { useState } from 'react'; export function Counter() { const [count, setCount] = useState(0); return ; } ``` **Step 2: Compose Server + Client** Server Components import Client Components; pass Server Components as children to avoid circular imports: ```javascript // Server Component: Can fetch data, import CC import { Counter } from './Counter'; async function Page() { const data = await db.getData(); return (

{data.title}

); } // ❌ WRONG: Client Component importing Server Component ('use client'); import ServerComponent from './ServerComponent'; // ERROR // ✅ RIGHT: Pass Server Component as children ; ``` ## Common Patterns **Interactivity at leaf nodes**: Server Component fetches data, passes to Client Component for interaction ```javascript async function ProductPage({ id }) { const product = await db.products.find(id); return ( <> ); } ``` **Server data in Client Component**: Pass as props (serialize data) ```javascript async function ServerComponent() { const data = await fetchData(); return ; } ``` **Server logic from Client**: Use Server Actions ```javascript async function ServerComponent() { async function serverAction() { 'use server'; await db.update(...); } return ; } ``` ## Example: Product Page with Cart ```javascript // 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 (
{product.name}

{product.name}

{product.description}

${product.price}

); } // 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 ( ); } // Server Component with real-time Client async function Dashboard() { const stats = await db.stats.getLatest(); return ( <> ); } // 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 ?
Active Users: {metrics.activeUsers}
:
Connecting...
; } // 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 (