The Virtual Panda
All writing
astrocloudflareprocess

How I ship a website in an afternoon now

Five sites, all on Astro, most on Cloudflare, all costing me about nothing. Here is the setup and the couple of things I would tell past me.

By Brenton Unger

Until a couple of weeks ago this site ran on a self-hosted Ghost install. It worked, but I was paying for a server to serve a handful of static pages, and every time I wanted to change the layout I had to remember how Handlebars themes worked. I replaced it in one commit on September 2nd, and I have not thought about the server since, because there is no server.

The same recipe has produced eidosmd.com, the Care Connect marketing site and its docs, my personal site (that one is on GitHub Pages, same idea), and this one. So, here is the recipe.

Astro for everything

Astro builds plain HTML. No framework on the client unless you ask for one. That is the whole reason I picked it, and it has held up: the pages are fast because there is nothing to be slow.

The parts I actually lean on:

  • Content collections. Products, services, and these posts are markdown files with a schema. The schema is a zod object, so a typo in frontmatter fails the build instead of showing up as a blank card. When I added a featured flag to products last week it was one line.
  • Images through the asset pipeline. I drop a PNG in src/assets, reference it from frontmatter, and the build spits out resized WebP at the widths I asked for. I do not run an image script anymore.
  • One route that is not static. The contact form on this site posts to a single endpoint that runs as a Worker and hands the message to Resend. Everything else is prerendered. That split is the sweet spot: static where it can be, a function where it has to be.

For documentation sites, Starlight on top of Astro is the fastest path I have found. Sidebar, search, dark mode, and i18n are handled, and you write markdown. Both eidosmd.com and the Care Connect guides are Starlight.

Cloudflare for hosting

Workers for this site because it has that one dynamic route. Pages for the pure static ones. Either way the deploy is pnpm build && wrangler deploy (or wrangler pages deploy), it takes about fifteen seconds, and the bill has been zero. The DNS is already there, so a custom domain is a click.

The one non-obvious thing I did: mail from the contact form goes out on a subdomain with its own SPF and DKIM, not the apex. If deliverability ever goes sideways it cannot touch my real inbox.

What I would tell past me

Stop picking a CMS. For a site one person maintains, markdown in the repo is the CMS. It is versioned, it is reviewable, and there is nothing to log in to.

Copy the design tokens, do not share them. The Care Connect marketing site uses the exact colors of the app, but as a copied file, not an import. A marketing copy edit should never be blocked behind an app build.

Put the whole thing in one command. pnpm deploy builds and ships. If it takes more than one line to deploy, you will put off deploying, and then you will put off writing.

It is super easy to over-engineer a website. The trick I keep relearning is that the boring stack wins, and the boring stack right now is Astro, markdown, and Cloudflare.