When a client asks for an editorial site — a company blog, a product documentation hub, a thought-leadership platform — the choice of stack shapes everything that follows: how fast the site loads, how painlessly editors push content, and whether the engineering cost scales sensibly as the site grows.
After evaluating a dozen combinations, we landed on Astro 5 + Keystatic 0.5 deployed on Cloudflare Workers. Here is what drove that decision, and what production use has taught us.
The baseline requirements
Our clients’ editorial sites share a consistent set of requirements:
- Speed that scores: Performance ≥ 90 in Core Web Vitals, because anything less hurts both organic rankings and ad revenue.
- Editor-friendly CMS: non-technical team members must be able to publish without developer help.
- SEO out of the box: structured data (Article, BreadcrumbList, FAQ JSON-LD), canonical tags, hreflang for bilingual content, and a sensible sitemap.
- Low operational overhead: no database to patch, no server to autoscale, no CMS subscription fee that shows up on the client invoice.
Most combinations hit two or three of these. Astro + Keystatic hits all four.
Why Astro
Astro’s rendering model starts from a principle that others treat as an optimization: every page is static unless you explicitly opt into server rendering. The result is that editorial content ships as pre-built HTML — no JavaScript hydration penalty, no SSR cold start, no database round-trip per request.
For editorial sites where 90% of traffic hits the same 20 articles, this matters. We measured a consistent 97–99 Lighthouse Performance score on pages generated by Astro versus 82–88 for the same content in a Next.js App Router build that leaned on ISR.
Astro also handles multilingual content naturally through its Content Collections API. Our standard editorial template ships with zh-TW and en content parity as a first-class schema constraint — not an afterthought added six months later when the client discovers they need a second language.
Why Keystatic
The CMS market splits into two unhelpful extremes: WordPress-class tools with enormous surface area that most editorial teams use at 5% capacity, and headless CMS subscriptions that charge per seat and per API call and require a developer to update the content schema.
Keystatic occupies the gap. Content lives in your own Git repository as plain Markdown files. Editors get a clean UI at /keystatic. Changes are Git commits — the same commits that trigger your CI pipeline, create audit trails, and survive the closure of any vendor.
The pricing model is a significant talking point with clients: Keystatic is free, open source, and the content storage cost is whatever GitHub costs (zero for public repos, a few dollars a month for private). There is no per-seat fee that scales uncomfortably as the editorial team grows.
The Cloudflare Workers advantage
Static sites can live on any CDN. We chose Cloudflare Workers specifically because it gives us a path from “static blog” to “edge-rendered application” without a stack change. When a client eventually needs user authentication, personalised content, or server-side A/B testing, we extend the Worker — we do not migrate the entire site.
The Keystatic admin UI requires a live server to handle GitHub OAuth callbacks. Running this on Cloudflare Workers means the CMS backend costs the same as the static site: essentially zero at editorial traffic volumes, with no separate backend deployment to maintain.
What we learned in production
Three things surprised us in practice.
The deployment setup is non-trivial the first time. Deploying Astro to Cloudflare Workers Static Assets involves specific configuration that differs from Cloudflare Pages. We documented 14 specific failure modes during our first deploy — everything from npm ci rejecting lock files generated with --legacy-peer-deps, to the Cloudflare Workers not_found_handling setting silently swallowing dynamic admin routes. The good news: every trap is solvable, and after the first project we’ve pre-baked every fix into our scaffolding tool so subsequent projects inherit the solutions automatically.
Keystatic 0.5 requires a GitHub App, not an OAuth App. This distinction is not immediately obvious from the documentation. It matters because GitHub Apps support fine-grained repository permissions and installation tokens, which is what Keystatic uses internally. OAuth Apps don’t interoperate. The only reliable diagnostic is to grep the compiled Worker bundle for the env var names it actually reads — the list is authoritative.
Static generation means deployment equals publishing. On a database-backed CMS, you can draft content in the database and choose when to surface it. With Astro’s static build, merging to main triggers a build and deploy. We handle this by filtering status !== "published" in getStaticPaths — drafts exist in the repo but are never rendered to HTML until the status flag is changed. Simple and reliable.
Is this the right stack for your project?
Astro + Keystatic is a strong fit for:
- Company blogs and thought-leadership sites with a small editorial team
- Product documentation with stable structure and infrequent schema changes
- Any site where SEO performance is a primary success metric
- Teams that want content in version control without a CMS vendor dependency
It is a worse fit for:
- Real-time content (live scores, financial data) — static builds introduce latency between content change and page update
- Large editorial teams with complex role-based access — Keystatic’s permission model is Git-native, meaning anyone who can push to the repo can publish
- Sites where the entire experience is an interactive application — Astro handles islands of interactivity well, but if every page is a client-side SPA, a framework built for that use case is cleaner
The common thread: editorial sites are a solved problem, and the solution should be boring. Fast static HTML, a Git-native CMS, edge delivery, and zero operational overhead. That is the stack.