Architecture & Engineering
Why we keep Client Components small
In Next.js, adding "use client" is easy. That simplicity can hide what the directive means.
A Client Component participates in the browser-side React application. Its code has to be delivered to the browser and hydrated. That is appropriate when the component needs state, effects, event handling, or browser APIs.
It is unnecessary when the component only needs to display content.
A navigation menu is a good example
One of our service-business sites has a fairly involved navigation system. The menu needs to open and close a service dropdown, respond to hover and click, close when the user clicks outside it, close on Escape, manage mobile navigation state, and clean up event listeners and timers.
That is browser behavior. A Client Component is the correct tool.
The service copy and page content do not become client-side just because the navigation is interactive.
The boundary should follow the interaction
A common anti-pattern is putting "use client" at the top of a large page because one child element needs a click handler.
That moves a much larger component tree into the client boundary.
We prefer to isolate the interactive piece. The page can remain server rendered while only the menu, gallery, filter, or form becomes client-side.
Why this helps performance
JavaScript has a different cost from HTML. After download it has to be parsed and executed, and React has to connect the rendered markup to the interactive component tree.
The less code we send for that job, the less work the browser has to do.
On a marketing site, much of the page has no interactive requirement at all.
It also improves reliability
Server-rendered content does not need a successful hydration pass in order to exist.
If analytics is slow, the service description is still there. If the phone is under load, the article is still readable. If JavaScript is delayed, the primary content does not vanish.
Small boundaries are easier to debug
When something interactive breaks, a narrow boundary is easier to inspect.
If the mobile menu owns its own state and effects, we know where to look. If half the site is one large client component, rendering and state behavior become coupled in ways that are harder to reason about.
We are not trying to eliminate JavaScript
Forms benefit from responsive submission states. Menus need interaction. Galleries may need controls. Applications can be mostly client-side by design.
The goal is not zero JavaScript.
The goal is to spend JavaScript where it creates value.
A visitor never sees the server/client boundary, but they notice that the page appears quickly, scrolling feels normal, tapping the menu works, and the site does not behave like a heavyweight application for no reason.
Client boundaries also affect the dependency graph
A Client Component can pull its imports into the browser bundle too.
That means a seemingly small decision at the top of a component tree can bring along utility libraries, icon systems, interaction helpers, and other dependencies that were never needed by the static content below it.
Keeping the boundary close to the interaction makes that dependency graph easier to inspect.
If a mobile menu needs state, the menu can own the state. The service page does not need to inherit the menu's runtime simply because both appear in the same layout.
Forms are another useful boundary
A contact form often needs submission state, validation feedback, and disabled-button behavior. Those are good reasons for browser-side React.
The content explaining the service above the form still does not need to become client-side.
On a gated-resource project, the dialog owns browser state while the trusted submission step lives in a small server route. That is a good example of different boundaries doing different jobs instead of pushing the whole feature into one runtime.
When a larger client surface is justified
Applications are different.
A dashboard with filters, live state, drag-and-drop behavior, local editing, or continuous user interaction may legitimately have a large client-side surface. In that case the browser is part of the product logic, not merely the presentation layer.
We do not force an application into a server-only philosophy.
The rule is proportionality. A marketing page should not inherit application-level runtime because one button toggles a menu.
This gives future optimization somewhere to start
When client code is isolated, bundle analysis becomes actionable. We can identify which interaction owns which dependency and decide whether the feature is worth the cost.
When most of the page is one client boundary, the answer is much murkier.
That is why we treat "use client" as an architectural boundary instead of a convenience directive.
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.