Server Components in practice
What moved to the server, what stayed on the client, and how much JavaScript we stopped shipping.

Why we moved
Our dashboard shipped 380 kB of JavaScript before the first chart appeared. Most of it rendered static tables that never changed after load.
Server Components let us keep those tables on the server and hydrate only the parts people actually interact with.
Drawing the client boundary
We used one rule: a component becomes a client component only if it needs state, effects or browser APIs.
- Filters and date pickers: client
- Tables and summaries: server
- Charts: server-rendered SVG, client only for tooltips
"use client";
export function RangePicker({ value, onChange }: Props) {
return <input type="date" value={value} onChange={(e) => onChange(e.target.value)} />;
}Need a hand?
Let’s build it together
Results
| Metric | Change |
|---|---|
| JavaScript shipped | −64% |
| Largest Contentful Paint | −1.1 s |
| Interaction to Next Paint | −40% |