Launch runbook: deploying to Cloudflare Pages and binding papalabs.dev
Once the content is in shape, going live is just this checklist. Same platform as my other Cloudflare Pages projects, except this one is purely static — even simpler.

A static site on Pages: the free tier is more than enough for a personal blog
Option 1: Git integration (recommended)
The better route — every git push deploys automatically:
- Push the blog repo to GitHub (private is fine);
- Cloudflare Dashboard → Workers & Pages → Create → Pages → Connect to Git, pick the repo;
- Build configuration:
| Setting | Value |
|---|---|
| Build command | npm run build |
| Build output directory | dist |
| Environment variable | NODE_VERSION = 22 |
NODE_VERSION is non-negotiable — the Pages default Node is old, and Astro 5 needs a recent one.
Use npm run build, not astro build: the Pagefind search index generation hangs off that npm script, and running astro directly ships a site with no working search.
Option 2: Direct upload with wrangler
If you’d rather not connect GitHub, build locally and push the folder:
npm run build
npx wrangler pages deploy dist --project-name papalabs-blog
Good for quick previews or before the repo is ready to share.
Binding the domain
- Pages project → Custom domains → add
papalabs.dev; - If the domain is already on Cloudflare, DNS wires itself up and HTTPS is ready within minutes;
- Add
www.papalabs.devtoo (it 301s to the apex automatically).
Pre-launch checklist
-
siteinastro.config.mjsis the production domain (it feeds absolute URLs in RSS and the sitemap); - Every unfinished article is marked
draft: true; - One local
npm run build && npm run previewpass — click through search, mindmaps and dark mode; - After launch, submit
https://papalabs.dev/sitemap-index.xmlto Google Search Console.
This is where the static-site bet pays off: no database to migrate, no secrets to configure, no server to babysit. The build output runs anywhere.