How to deploy Astro on Cloudflare Pages
Built 2026-09-22
Stack Astro 5 static build · Cloudflare Pages · Cloudflare Registrar + DNS · GitHub
Total cost $10.46/year, all in
mossbysea runs on Astro 5, built static, pushed to GitHub, and served from Cloudflare Pages. This is the walkthrough I wish I’d had before the first push — the parts that are one checkbox in the dashboard and the one setting that silently breaks the build if you skip it.
If your site is already live and something went wrong after deploy, that’s a different article: eight things that broke on Cloudflare Pages. This one stops at “it’s on a real domain.”
What you need before you start
- An Astro project with a working local build (
npm run buildsucceeds, output lands indist). - A GitHub repository with that project. Cloudflare Pages pulls from GitHub directly; you don’t run any deploy command yourself.
- A Cloudflare account (free tier is enough) and, later, a domain in Cloudflare Registrar or transferred in.
That’s it. No server, no container, no database.
Step 1 — Create the Pages project
In the Cloudflare dashboard: Workers & Pages → Create → Pages → Connect to Git. Authorize GitHub, pick the repo, and Cloudflare offers a framework preset. Choose Astro.
The preset fills in two fields for you:
- Build command:
npm run build - Build output directory:
dist
Don’t change them unless your project is non-standard. Astro’s default static output already goes to dist, so the preset is correct out of the box.
Step 2 — Set the Node version (the gotcha)
This is the one setting that bites people. Cloudflare Pages builds on a default Node version that can be older than what Astro 5 needs. Astro 5 requires Node 18.17.1, 20.3.0, or 22+. If the build container runs an older Node, npm run build fails with a cryptic engine error and the deploy shows as failed before it even runs your code.
Two ways to pin it:
- In the dashboard: Settings → Builds & deployments → Build configuration → Node.js version and set it to 22 (or 20).
- Or add it to
package.jsonso it travels with the repo:
{
"engines": {
"node": ">=20.3.0"
}
}
Do one of these before the first build. I set it in the dashboard and forgot it existed — the build failed once, the error pointed at Astro’s engine check, and the fix was this single dropdown.
Step 3 — Push and watch the first deploy
Commit and push to the branch you connected (I use main). Cloudflare picks it up automatically, runs the build, and gives you a *.pages.dev URL when it’s green.
Open that URL. It’s a real, public, HTTPS URL — your site is live before you’ve touched DNS. This is also the moment to click through every page, because the pages.dev URL serves the exact build that will later sit on your domain.
Step 4 — Connect the custom domain
Back in the Pages project: Custom domains → Set up a domain. Enter it, and Cloudflare tells you which DNS records to add (usually a CNAME to the pages.dev host, or it manages the record for you if the domain is already in Cloudflare).
Two things worth knowing here:
- Don’t disable the
workers.devsubdomain yet. It’s tempting to clean it up, but aCNAMEor a setting can still point at it — and turning it off takes the thing yourwwwdepends on down with it. That specific failure has its own write-up: Cloudflare Pages www down: fix Error 1016. - HTTPS is automatic. Cloudflare issues and renews the certificate; you don’t install one.
Step 5 — Confirm the loop
Make a small edit, push, and watch it appear on the custom domain within a minute or two. That push-to-live loop is the whole point: write, commit, it’s published. No build server to babysit, no FTP.
What this costs
With the domain in Cloudflare Registrar and DNS, Email Routing, and Pages all on the free tier, the only line item is the domain itself — about $10.46/year for the .com. Hosting, SSL, and email forwarding are included. That’s the entire bill for a live, HTTPS, custom-domain site.
Where to go next
The deploy is the easy part. The interesting failures show up after you’re live, and they deserve their own pages:
- Cloudflare Pages www down: fix Error 1016 — what happens when disabling
workers.devtakeswwwdown with it, and the two ways out. - Cloudflare Email Routing: setup and catches — free custom-domain forwarding, the destination-address trap, and why it receives but can’t send.
- Cloudflare Pages redirects: the 301 playbook — keep old URLs alive when you rename or restructure, without 404s.
- Astro build fails on Cloudflare Pages: fixes — the Node-version, output-dir, and install-timeout causes, and the fixes.
Everything else — the dashboard move, the dead URL after a green build, the browser-cache false alarm, the new-domain delay — is collected in eight things that broke on Cloudflare Pages. Read that before you congratulate yourself.