Two years ago I moved this site to a server-rendered stack chasing features I used maybe twice. Last month I moved it back to something that just builds to files and sits on a CDN. It was, without exaggeration, the fastest performance win I’ve shipped all year.
Why static still wins
Most of what a blog needs — typography, a fast first paint, content that doesn’t change per request — is exactly what static output is best at. The server work I’d added wasn’t serving readers; it was serving my own curiosity about the stack.
The fastest request is the one your server never has to think about.
The one place I kept dynamic behavior was content collections — typed frontmatter, checked at build time:
const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
schema: z.object({
title: z.string(),
pubDate: z.coerce.date(),
}),
});
If a post’s frontmatter is wrong, the build fails before it ever reaches a reader. That’s the whole appeal — correctness as a byproduct of simplicity, not a framework bolted on top of it.
None of this means server rendering is wrong for every project. It means it was wrong for this one — a handful of pages that change a few times a month, read by people who just want the words to show up fast.