React Server Components Cheat Sheet
Syntax and rules for RSC: server vs client component boundaries, the 'use client' directive, async components, and data fetching.
Default Server Component
Components are Server Components by default (in RSC-enabled frameworks like Next.js App Router) — no directive needed.
// app/products/page.tsx — runs only on the serverimport { db } from '@/lib/db'export default async function ProductsPage() { const products = await db.product.findMany() // direct DB access, no API route return ( <ul> {products.map((p) => ( <li key={p.id}>{p.name}</li> ))} </ul> )}
'use client' Boundary
Opt a subtree into client rendering when you need interactivity, state, or browser APIs.
'use client'import { useState } from 'react'export function LikeButton({ initialLikes }: { initialLikes: number }) { const [likes, setLikes] = useState(initialLikes) return <button onClick={() => setLikes(likes + 1)}>{likes} likes</button>}// server component passes serializable props down// export default async function Page() {// const post = await getPost()// return <LikeButton initialLikes={post.likes} />// }
Passing Server Components as Children
Render a Server Component inside a Client Component via the children prop, keeping the child server-rendered.
'use client'export function ClientShell({ children }: { children: React.ReactNode }) { const [open, setOpen] = useState(false) return <div onClick={() => setOpen(!open)}>{open && children}</div>}// server component// import { ClientShell } from './ClientShell'// export default async function Page() {// const data = await fetchData() // stays server-only// return <ClientShell><ServerRenderedDetails data={data} /></ClientShell>// }
Server Actions
Call server-only mutation functions directly from client forms without hand-rolling an API route.
// app/actions.ts'use server'export async function createTodo(formData: FormData) { const title = formData.get('title') as string await db.todo.create({ data: { title } })}// app/todo-form.tsximport { createTodo } from './actions'export function TodoForm() { return ( <form action={createTodo}> <input name="title" /> <button type="submit">Add</button> </form> )}
Server vs Client Component Rules
What you can/can't do on each side of the boundary.
- Server Components- can be async, access DB/filesystem/secrets directly, never re-render on the client, ship zero JS
- Client Components ('use client')- can use useState/useEffect/browser APIs, hydrate and re-render like classic React
- Props crossing the boundary- must be serializable (no functions, class instances, or Dates without a transform)
- Server Components inside Client Components- allowed only via the children/slot pattern, not by direct import
- 'use server' (Server Actions)- marks a function callable from the client that always executes on the server
The 'use client' directive marks the top of a subtree, not a single file in isolation — everything that file imports (unless it's also marked, or is a shared library) gets bundled into the client boundary too, so put it as low in the tree as possible to keep the server-rendered surface large.
Explore Topics
Professional Web Designing Services
- Responsive Websites
- E-commerce Solutions
- SEO Friendly Design
- Fast & Secure
- Support & Maintenance