React Server Components (RSCs) run exclusively on the server and never ship JavaScript to the client. Unlike Client Components (marked with `'use client'`), RSCs can directly access databases, file systems, and server-side secrets without exposing them. The key difference is that RSCs produce static HTML output, while Client Components hydrate in the browser and support interactivity like `useState` and `useEffect`.
In a Server Component you can use `async/await` directly in the component body — no `useEffect` or `useState` needed. For example: `async function Page() { const data = await db.query('SELECT * FROM posts'); return <PostList posts={data} />; }`. Next.js extends `fetch()` with automatic deduplication and caching via `next: { revalidate: 60 }` for ISR, or `cache: 'no-store'` for fully dynamic data.
You pass serialisable data as props from the Server Component to the Client Component — strings, numbers, plain objects, and arrays all work. Importantly, you cannot pass functions, class instances, or Promises directly as props across the boundary. A common pattern is to fetch in the server component, select only the fields the client needs, and pass that subset down to keep the bundle lean and avoid leaking sensitive fields.
Yes — and this is the recommended composition pattern. A Server Component can import and render a Client Component, passing server-fetched data as props. However, a Client Component cannot import a Server Component (doing so would pull server-only code into the client bundle). The `children` pattern is a useful workaround: a Client Component can accept `children` as a prop and a Server Component can pass server-rendered JSX into that slot.
The `server-only` package throws a build-time error if a module marked with it is accidentally imported into a Client Component. Add `import 'server-only'` at the top of any file that must stay on the server — database clients, secret-consuming utilities, etc. It's a safety guardrail that catches boundary violations early rather than at runtime.
Here's a minimal Server Action example: `'use server'; export async function createPost(formData: FormData) { const title = formData.get('title') as string; await db.insert({ title }); revalidatePath('/posts'); }`. You reference this action in a `<form action={createPost}>` element or call it directly from a Client Component button handler. No API route needed — Next.js handles the RPC layer automatically.
GPT-4o may produce inaccurate information. Consider checking important information.