Skip to main content
Practice Problems

Server and client component patterns in Next.js

Server and Client Component Patterns

Knowing when to use Server vs Client Components and how to compose them correctly is one of the most important Next.js skills.


The Rule

NeedUse
Fetch data, access DBServer Component
Static content, SEOServer Component
useState, useEffectClient Component
onClick, onChangeClient Component
Browser APIs (window, localStorage)Client Component
Reduce JS bundleServer Component

Pattern 1: Push Client Components Down

Move interactivity to the smallest possible Client Component:

tsx
// โœ… GOOD โ€” only the interactive part is a Client Component // app/blog/[slug]/page.tsx (Server Component) export default async function BlogPost({ params }: { params: Promise<{ slug: string }> }) { const { slug } = await params; const post = await getPost(slug); return ( <article> <h1>{post.title}</h1> <p>{post.content}</p> {/* Static โ€” stays server */} <ShareButton url={post.url} /> {/* Only this is a Client Component */} </article> ); } // components/ShareButton.tsx "use client"; export function ShareButton({ url }: { url: string }) { return <button onClick={() => navigator.share({ url })}>Share</button>; }
tsx
// โŒ BAD โ€” entire page is Client Component because of one button "use client"; export default function BlogPost() { const [post, setPost] = useState(null); useEffect(() => { fetchPost().then(setPost) }, []); // Everything runs on client, large JS bundle }

Pattern 2: Server Component as children

Pass Server Components through Client Components using children:

tsx
// ClientWrapper.tsx "use client"; import { useState } from "react"; export function Accordion({ title, children }: { title: string; children: React.ReactNode; }) { const [isOpen, setIsOpen] = useState(false); return ( <div> <button onClick={() => setIsOpen(!isOpen)}>{title}</button> {isOpen && <div>{children}</div>} </div> ); } // page.tsx (Server Component) export default async function Page() { const data = await fetchData(); // Server-side fetch return ( <Accordion title="Details"> {/* This ServerContent runs on server, even inside Client Accordion */} <ServerContent data={data} /> </Accordion> ); }

Pattern 3: Fetch in Server, Interact in Client

tsx
// app/products/page.tsx (Server Component) export default async function ProductsPage() { const products = await getProducts(); // Server: no API call needed return <ProductGrid products={products} />; } // components/ProductGrid.tsx "use client"; export function ProductGrid({ products }: { products: Product[] }) { const [filter, setFilter] = useState(""); const filtered = products.filter(p => p.name.includes(filter)); return ( <div> <input value={filter} onChange={e => setFilter(e.target.value)} /> {filtered.map(p => <ProductCard key={p.id} product={p} />)} </div> ); }

Pattern 4: Context Providers

Wrap Client providers at the layout level:

tsx
// providers.tsx "use client"; import { ThemeProvider } from "next-themes"; import { QueryClientProvider } from "@tanstack/react-query"; export function Providers({ children }: { children: React.ReactNode }) { return ( <ThemeProvider> <QueryClientProvider client={queryClient}> {children} </QueryClientProvider> </ThemeProvider> ); } // app/layout.tsx (Server Component) import { Providers } from "./providers"; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html> <body> <Providers> {children} {/* Can still be Server Components */} </Providers> </body> </html> ); }

Common Mistakes

tsx
// โŒ Importing Client Component and passing function import { ClientComp } from "./ClientComp"; export default function Server() { // Cannot pass functions from Server to Client return <ClientComp onClick={() => console.log("hi")} />; // โŒ Error } // โœ… Define the handler in the Client Component itself "use client"; export function ClientComp() { return <button onClick={() => console.log("hi")}>Click</button>; }

Quick Decision Guide

Does it need state, effects, or event handlers? โ†’ Client Component ("use client") Does it fetch data or access server resources? โ†’ Server Component (default) Is it purely presentational (just props โ†’ JSX)? โ†’ Server Component (default, keeps bundle small) Does it use browser APIs (window, localStorage)? โ†’ Client Component ("use client")

Important:

Default to Server Components and only add "use client" where needed. Push Client Components to the leaves of your component tree. Use the children pattern to nest Server Components inside Client Components. Fetch data in Server Components and pass it as serializable props to Client Components for interactivity.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems