Papa Labs

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.

Cloudflare Pages product page

A static site on Pages: the free tier is more than enough for a personal blog

The better route — every git push deploys automatically:

  1. Push the blog repo to GitHub (private is fine);
  2. Cloudflare Dashboard → Workers & Pages → Create → Pages → Connect to Git, pick the repo;
  3. Build configuration:
SettingValue
Build commandnpm run build
Build output directorydist
Environment variableNODE_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

  1. Pages project → Custom domains → add papalabs.dev;
  2. If the domain is already on Cloudflare, DNS wires itself up and HTTPS is ready within minutes;
  3. Add www.papalabs.dev too (it 301s to the apex automatically).

Pre-launch checklist

  • site in astro.config.mjs is 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 preview pass — click through search, mindmaps and dark mode;
  • After launch, submit https://papalabs.dev/sitemap-index.xml to 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.

← All posts