A Next.js Server vs Client Component Boundary Checklist

Use this Next.js server versus client component boundary checklist to stop AI-generated App Router code from mixing data, hooks, and browser logic in the wrong place.

Next.jsReactServer ComponentsClient Components

Why boundary mistakes get through review so easily

AI-generated App Router code often looks plausible because both server and client components can render the same JSX shape. The mistake is usually not visual. It sits in where data is fetched, where browser APIs are read, and where stateful interactivity begins.

That creates a specific review problem. A diff can look tidy while still pushing fetch logic into the client, leaking browser-only code into server paths, or marking whole trees with use client because that was the easiest way for the model to make the code compile.

The checklist that catches most App Router boundary bugs

Keep the review tight. You are checking whether the code chose the right side of the boundary, not whether the file structure feels elegant.

  • Data source: is data fetched on the server by default, or was it moved client-side only to make hooks easier to generate?
  • Browser dependency: does this component actually need browser APIs, local state, or event handlers before adding use client?
  • Serialization: are props crossing the boundary serializable, or is the code trying to pass functions, class instances, or live connections?
  • Tree size: did one interactive child cause the whole parent subtree to become client-rendered?
  • Mutation path: if the UI mutates data, is the server or action boundary still explicit instead of hidden inside a client fetch patch?
  • Caching intent: does the chosen boundary preserve the caching and streaming behavior the page should have?

Questions worth asking in pull requests

Good review comments force the author to explain tradeoffs. Ask why this file is client-rendered, what would break if the parent stayed server-side, and which prop must cross the boundary.

Another useful question is whether the interactive island can be pushed lower in the tree. That one question often removes a large accidental client surface created by AI-generated scaffolding.

A safe migration order when the boundary is already blurry

Start by moving pure data fetches and static layout back to server components. Then isolate the smallest interactive leaf that truly needs hooks, state, or DOM access. Only after that should you refine mutation and caching behavior.

If the code still feels confusing after that split, the draft is probably carrying too much generated structure. Delete the wrapper components and rebuild the tree around the actual boundary instead of preserving accidental complexity.

Turn reading into signal

Read the Dispatch sample issue

If this article matches the way you already work, the next step should not be another generic landing page. Move into the exact paid surface this article is meant to test, then compare that demand against the alternate path.

Early signal form

Read the Dispatch sample issue

Tell me which offer matters, whether you would pay, and what budget feels realistic.

One sharp update when the pilot is ready. No daily noise.

Keep reading

Related React articles