tezvyn:

Server vs. Client Components in Next.js

AI-drafted, machine-checkedintermediate

Next.js forces a render boundary. Server Components generate HTML without sending JavaScript, while Client Components ship JS for interactivity. The footgun is importing a heavy library into a Server Component via a child, bloating the client bundle.

WHY IT EXISTS: Before the App Router, every React component shipped to the browser, even if it only displayed static data fetched from a database. That meant larger JavaScript bundles, slower hydration, and API keys or database queries exposed only by virtue of needing client-side code to render. Next.js needed a way to keep React's component model while letting parts of the tree run exclusively on the server, sending only HTML to the browser.

THE MENTAL MODEL: Think of your UI as a document assembled in two different factories. The server factory builds the structural frame, fetches data, and paints the initial picture using zero browser code. The client factory adds the moving parts: buttons that click, forms that validate, animations that respond to the mouse. Every component must choose its factory before it ships. A server-built piece can contain client-built pieces inside it, but once a subtree crosses into the client factory, everything inside that subtree is assumed to need the browser.

HOW IT WORKS: Server Components render during the request on the server. They can read files, query a database, and import server-only modules. The output is a JSON-like stream that the Next.js runtime uses to build HTML and merge it with Client Component placeholders. Client Components are pre-rendered on the server for the initial HTML, but their JavaScript is also sent to the browser so React can hydrate them and attach event listeners. The boundary is created by the use client directive at the top of a file. Any component imported into a file marked with use client automatically becomes part of the client bundle, even if its own file has no directive.

WHEN TO USE IT: Use Server Components for layouts, pages that read from a database, static content, and any UI that does not need event listeners or browser APIs. They reduce bundle size and keep sensitive logic on the server. Use Client Components for interactive elements like date pickers, shopping carts, charts that rely on window size, and anything using useState, useEffect, or browser-only libraries.

WHEN NOT TO USE IT: Do not use a Client Component for a purely static hero section just because it lives inside an interactive page. Do not fetch sensitive data inside a Client Component if you can fetch it on the server. Avoid marking an entire page as a Client Component when only a small island at the bottom needs interactivity; that forces the whole tree to ship JavaScript unnecessarily.

ONE CANONICAL EXAMPLE: Imagine a product page. The shell, navigation, and product details are Server Components that fetch inventory and descriptions directly from Postgres. The color selector and Add to Cart button live in a Client Component nested inside the page. The product data flows down as props from the server to the client island. If a developer accidentally imports a large charting library into the Server Component file that is only used inside the Client Component, the bundler still sends that library to the browser because the import graph crosses the use client boundary, silently inflating the bundle.

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.