Server Components Overview
React Server Components run on the server: zero client JS for their logic, async data, and composition with client leaves.
- react
- server-components
Server Components (RSC) render on the server into a special payload the client hydrates selectively. They can be async, read databases and secrets (with care), and do not ship their own component logic as client JS. Interactive islands opt into Client Components.
Docs: Server Components, Next.js.
What you gain
| Benefit | Why |
|---|---|
| Smaller bundles | Server-only code never goes to the client |
| Direct data access | await db.query in the component |
| Secure by default | Secrets stay server-side |
| Streaming | Frameworks can stream UI as data resolves |
What you cannot do on the server
useState,useEffect, browser DOM APIs- Event handlers like
onClickon the server component itself - Importing client-only libraries without a client boundary
Composition
// Server
async function Notes() {
const notes = await getNotes();
return (
<ul>
{notes.map((n) => (
<li key={n.id}>
{n.title}
<EditButton noteId={n.id} /> {/* client */}
</li>
))}
</ul>
);
}
Keep client boundaries at interactive leaves.
Mental model versus classic SSR
Classic SSR still sent a full client React tree to hydrate. RSC can keep large pure UI server-only. Hydration applies mainly to client islands. Mismatches still matter for those islands (hydration).
Interview out-loud
“Server Components render on the server, can be async, and avoid shipping their logic to the client. I fetch data on the server, pass serializable props to client children, and use composition so client shells wrap server content via children. Hooks and browser APIs require Client Components.”
Related on this site
Further reading
Edge cases worth rehearsing
Interviewers and production incidents cluster around the same edges: first render versus update, empty and loading states, Strict Mode double setup, concurrent interruptions, and what happens when identity (key, route params, user id) changes mid-edit. Walk one concrete user journey end-to-end — open, edit, navigate away, come back — and say which state survives.
Prefer fixing data flow and ownership before reaching for memoization or micro-optimizations. Prefer event handlers over effects when a user action is the trigger. Prefer deriving values during render over mirroring props into state. Prefer stable list keys from business ids. Measure with the profiler when performance is the claim.
When you cite an API, mention one failure mode: abort on unmount, serializable props across server/client boundaries, focus restoration for dialogs, or cache invalidation after a mutation. Specific beats generic every time.
Edge cases worth rehearsing
Interviewers and production incidents cluster around the same edges: first render versus update, empty and loading states, Strict Mode double setup, concurrent interruptions, and what happens when identity (key, route params, user id) changes mid-edit. Walk one concrete user journey end-to-end — open, edit, navigate away, come back — and say which state survives.
Prefer fixing data flow and ownership before reaching for memoization or micro-optimizations. Prefer event handlers over effects when a user action is the trigger. Prefer deriving values during render over mirroring props into state. Prefer stable list keys from business ids. Measure with the profiler when performance is the claim.
When you cite an API, mention one failure mode: abort on unmount, serializable props across server/client boundaries, focus restoration for dialogs, or cache invalidation after a mutation. Specific beats generic every time.
Related guides
- useCopyToClipboard HookCopy text with navigator.clipboard, fallback execCommand, transient copied state, and permissions that fail in insecure contexts.
- useDebouncedValue HookDebounce a changing value in React without firing effects on every keystroke. Cleanup, leading vs trailing, and the stale timer that updates unmounted state.
- useEventListener HookAttach a window, document, or element listener with a stable handler ref so you do not rebind on every render. Capture option and target changes.
- useFetch With AbortControllerFetch in an effect with a signal, ignore aborted errors, and prevent the slow response from winning a race after the url changes.
- useIdle HookDetect idle users: reset a timer on input events, fire idle after timeout, and decide whether mount starts the timer immediately.