Boundary design
Use server components for data-intensive composition and client components for interaction-heavy islands. This keeps payloads lean.
State isolation
Isolate stateful UI concerns to small client components. Avoid pushing global state down the full tree when route-level fetches are enough.
Component contracts
Define clear contracts for each boundary:
- Server component returns serialized view model
- Client component receives stable props and callbacks
- Shared types encode nullable and loading cases
type DashboardSummary = {
creditsRemaining: number;
tasksToday: number;
spendUsd: number;
};Migration plan
Migrate in slices: pick one route, split rendering layers, then benchmark. Repeat until your highest-traffic surfaces are server-first.