Architecture & Engineering

Server Components and Client Components

One of the biggest architecture decisions in a modern Next.js site is deciding what needs to run in the browser and what does not.

One of the biggest architecture decisions in a modern Next.js site is deciding what needs to run in the browser and what does not.

Server Components are the default

Most content pages do not need browser-side state. A heading, paragraph, service list, article, or portfolio page can usually be rendered on the server. Keeping those components on the server means less JavaScript is sent to the visitor. The browser receives the finished result instead of receiving a large application that must reconstruct the page.

Client Components are for interaction

A component belongs on the client when it genuinely needs browser APIs, local state, event-driven behavior, or interactive controls. Mobile navigation, form state, sliders, and similar interface behavior may need a client boundary. The mistake is marking an entire page as client-side because one small feature needs interaction.

Boundaries should stay narrow

We try to isolate interactive behavior to the smallest practical component. The rest of the page can remain server rendered. This keeps the bundle smaller and reduces hydration work. It also makes the code easier to understand because the interactive parts are obvious.

Why this matters for business sites

A lot of marketing websites are treated like web apps even when they do not need to be. That adds runtime work without adding business value. Our sites tend to perform well because we avoid making the browser do work the server can already finish. Fast sites are often the result of restraint, not exotic optimization.

The boundary is visible in real features

A server-rendered page can contain a client-side gallery without becoming a client-rendered page. The gallery owns its selected image, lightbox state, keyboard events, and cleanup. The route around it can still load content on the server and send the rest of the document as finished HTML.

The same pattern appears in a gated resource flow. A small Client Component owns whether the modal is open, the current form values, submission status, Escape handling, and body-scroll locking. The actual request validation and provider forwarding happen through a server route.

That is the split we want: browser concerns in the browser, trusted server concerns on the server, ordinary content rendered without unnecessary hydration.

Client boundaries affect bundle size

Adding "use client" changes what has to participate in the browser bundle. If the directive sits high in the component tree, a large amount of otherwise static interface can cross that boundary. We therefore place it as low as practical around the interactive feature. The component can still receive serializable data from a Server Component parent.

This keeps the page architecture clear and helps our JavaScript budget.

Server Components can read source data directly

Our MDX loaders, filesystem readers, and build-time registries belong comfortably on the server. They can read content files without exposing that filesystem behavior to the browser. The page gets the resulting data model, not the implementation used to retrieve it. That is one of the reasons repository content works well with the App Router.

Not every server-rendered component is static forever

A Server Component can still render at request time when the route needs request-specific data. Server-first does not mean static-only. It means we choose the server as the default execution environment for work that does not require browser APIs. Likewise, Client Components are not a failure. They are the correct tool for stateful interaction.

The quality of the architecture comes from putting the boundary where the responsibility changes.

The question we ask during review

When a component needs useState, useEffect, browser events, or window, it probably belongs on the client. When it only receives data and renders markup, we ask why the browser needs to execute it. That simple review question prevents a surprising amount of accidental client-side application weight.

From explanation to proof

Where this connects to the work

This category is the clearest technical proof that our sites are built as maintainable software rather than assembled as isolated pages.