The older JAMstack pitch was simple: prebuild the pages, ship them close to users, and avoid unnecessary servers.
That idea is still strong. What changed is the shape of modern static sites. A portfolio, docs hub, or product marketing site can now include typed content, local search, feed generation, animated interaction, and route-level metadata without turning into a backend project.
Static does not mean inert
The important distinction is between runtime data and runtime interaction. A blog post does not need a server request to render. A search dialog, springy project card, or physics token field can still hydrate only where needed.
That is the useful App Router pattern for this site:
- Server components render content and metadata.
- Local MDX keeps writing editable.
- Zod validates frontmatter before publishing.
- Pagefind indexes exported HTML.
- Client components own only the interaction layer.
Migration pressure points
The risky parts are rarely the pages themselves. They are the contracts between systems:
- Does draft filtering match across blog, tags, RSS, sitemap, and search?
- Do dynamic routes have deterministic static params?
- Are images served from public paths instead of framework-specific asset pipelines?
- Do animations respect reduced motion and avoid layout shift?
Answer those questions early and the migration becomes much less dramatic.
What I optimize for
I want static sites that are easy to publish, easy to inspect, and hard to accidentally break. The stack matters, but the contract matters more: typed content in, predictable pages out, and interaction isolated enough that the site remains fast when the visual layer gets ambitious.

