---
name: react-server-components-pro
description: "RSC patterns — server/client boundary, streaming, Suspense, the data-fetching tree that doesn't waterfall. A senior React engineer for Server Components: where to draw the server/client boundary, parallel vs sequential data fetching, Suspense + streaming SSR, error boundaries, and the patterns that prevent the dreaded N+1 waterfall."
license: MIT
---

# React Server Components Pro

A senior-level reviewer and pair programmer for React Server Components. It helps you decide what runs on the server versus the client, structure data fetching so requests run in parallel instead of cascading, and wire up Suspense and streaming so users see content before every query resolves. Aimed at developers building on the Next.js App Router (or any RSC-capable framework) who keep hitting hydration mismatches, request waterfalls, and confusing `'use client'` errors.

## When to use it

- You see a "waterfall": a page that fetches user → then posts → then comments sequentially, each blocking the next.
- A component throws "You're importing a component that needs `useState`/`useEffect`... add `'use client'`" and you're not sure where the boundary belongs.
- You want a slow widget (a feed, a dashboard panel) to stream in without holding up the rest of the page.
- You're passing functions or class instances across the server/client boundary and getting serialization errors.
- A `fetch` runs once per row and you suspect an N+1.

## How it works

It reasons about the real RSC model and the App Router APIs:

- **Boundaries:** `'use client'` marks the entry into the client tree; `'use server'` marks Server Actions. It pushes the boundary down so interactive leaves are client components while data-fetching shells stay on the server.
- **Parallel fetching:** kick off `fetch`/DB calls without `await`, then `await Promise.all([...])`, or render independent children that each fetch on their own. It leans on React's automatic `fetch` request deduping and Next's `cache()`.
- **Streaming:** `loading.tsx`, `<Suspense fallback={...}>`, and component-level boundaries so the shell flushes first and slow subtrees stream in.
- **Errors:** `error.tsx` boundaries and pairing Suspense with error handling.

## Example

```tsx
// app/dashboard/page.tsx — parallel, streamed
import { Suspense } from 'react'

export default function Page() {
  const userP = getUser()        // start, don't await
  const statsP = getStats()
  return (
    <>
      <Header userPromise={userP} />
      <Suspense fallback={<StatsSkeleton />}>
        <Stats statsPromise={statsP} />  {/* streams in later */}
      </Suspense>
    </>
  )
}
```

## Tips & gotchas

- Adding `'use client'` to a parent forces every imported child into the client bundle. Keep it on leaves and pass server-rendered children as `props.children`.
- You can pass a Promise from a server component into a client component and unwrap it with `use()` — this streams data without blocking the server render.
- `await`-ing each fetch on its own line is the most common silent waterfall. Start promises early, await together.
- Server Actions (`'use server'`) must take serializable args; you can't hand a client a server function's closure over non-serializable values.

## FAQ

**Does this only work with Next.js?** The patterns target the App Router, but the boundary/streaming advice applies to any RSC framework (Remix-on-RSC, custom setups).

**Will it convert my existing Pages Router app?** It advises on migration strategy and per-component conversion, but won't blindly rewrite a whole app.

**How does it catch waterfalls?** It traces the `await` sequence in your render tree and flags dependent fetches that could run concurrently.
