Server Components, One Year Later
This post started as a note to my future self. Every few months I relearn the same lessons about server-side rendering, so this time I'm writing them down.
Most of the complexity was accidental. Over the years we'd layered three different approaches to server-side rendering on top of each other, and each one made sense at the time.
The problem
When we finally measured, the numbers were worse than anyone guessed. Around 43% of the time spent on a typical change went into working around server-side rendering rather than building anything.
The first symptom was subtle. Nothing failed outright, but server-side rendering kept drifting in the wrong direction, and every fix seemed to make the next one harder.
The fix
The key insight was to treat server-side rendering as part of the interface rather than an implementation detail. Once we did that, most of the other decisions followed naturally.
The core of it looks like this:
export function debounce<T extends (...args: any[]) => void>(fn: T, wait = 200) {
let timer: ReturnType<typeof setTimeout> | undefined;
return (...args: Parameters<T>) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), wait);
};
}
It's tempting to generalize this into a library. Resist that urge until you've needed it in at least three places.
A few things that helped along the way:
- Measure before and after, even if it's just a rough number in a spreadsheet.
- Delete dead code aggressively; it's the cheapest refactor there is.
- Make the default the safe choice, not just the documented one.
What it cost us
There are cases where this falls apart. If your team is very small or your traffic is very spiky, the extra moving parts may not pay for themselves.
None of this is free. The new approach is a bit more verbose, and newcomers occasionally ask why we don't just use Astro for everything. That's a fair question with a boring answer: we tried, and it made server-side rendering harder to reason about.
Closing thoughts
Six months in, nobody on the team wants to go back. That's about the best review a change like this can get.