How to Deploy an Astro Content Site on Cloudflare Pages
A hands-on walkthrough of building a Git-backed content site with Astro and shipping it to Cloudflare Pages with zero database.
Why Astro + Cloudflare
Astro is a content-first framework that ships zero JavaScript by default. Paired
with Cloudflare Pages, you get a globally distributed, fast static site — and with
the @astrojs/cloudflare adapter you can keep server-rendered admin routes too.
This tutorial builds devnotes: posts and blog posts live as MDX files in Git, and a small admin editor commits new content via the GitHub API, which triggers a fresh Pages build. No database required.
Prerequisites
- Node.js 20+
- A Cloudflare account (free tier is enough)
- A GitHub repository for your content
Step 1 — Scaffold the project
npm create astro@latest -- --template minimal
cd your-project
npm install @astrojs/cloudflare @astrojs/mdx @astrojs/sitemap
Step 2 — Configure the Cloudflare adapter
In astro.config.mjs, set the output to server and add the adapter:
import cloudflare from "@astrojs/cloudflare";
import mdx from "@astrojs/mdx";
export default {
site: "https://your-domain.pages.dev",
output: "server",
adapter: cloudflare(),
integrations: [mdx()],
};
Step 3 — Author content as MDX
Create src/content/posts/my-post.mdx:
---
title: "My First Post"
description: "A short summary for listings and search."
difficulty: "beginner"
tags: ["intro"]
category: "Web"
---
## Section one
Write your body in Markdown.
Step 4 — Deploy
- Push to GitHub.
- In Cloudflare Pages, connect the repo and set the build command to
npm run buildand the output directory todist. - Add your secrets (
ADMIN_PASSWORD,GITHUB_TOKEN, …) in the dashboard.
For a local preview of the finished build, run npm run build and use the
project’s documented preview command. For the command-line side of Cloudflare
projects, see How to Set Up Wrangler for Cloudflare Workers Development. Keep production deploys tied to the intended branch and review the generated output before publishing.
Every push to the production branch triggers a build, and pull requests get
automatic preview deployments on *.pages.dev — point your reviewer at the
preview URL instead of screenshots.
Step 5 — URLs, canonicals, and the sitemap
A few details separate a site that ranks from one that confuses crawlers:
- Set
siteinastro.config.mjs— the sitemap and every canonical tag derive from it. - Pick one URL form. Pages 308-redirects
https://site.com/posttohttps://site.com/post/; if your canonical tags point at the no-slash form they point at a redirect, and search engines stop trusting them. Canonicals must match what the sitemap advertises. - The sitemap plugin (
@astrojs/sitemap) emits only pages that actually built — drafts never appear — so it doubles as a check that nothing is accidentally missing.
Troubleshooting
- Blank pages after deploy: ensure
siteinastro.config.mjsis set — canonical URLs and the sitemap depend on it. - Admin 401s: check
GITHUB_TOKENhasContents: Read/Writeon the repo. - Pages builds fail while local builds pass: CI runs
npm ci, which requirespackage-lock.jsonto be in sync withpackage.json. If CI saysMissing: <package> from lock file, runnpm installlocally and commit the lockfile. - Wrong trailing-slash behavior: the redirects come from Pages itself; to keep URLs consistent, link to slash-form URLs everywhere and make canonicals match.
Connect checks and content workflow
Run the build locally before opening a pull request, then let CI repeat the same command on every change. GitHub Actions for CI/CD covers that automation. If the site has a browser editor, keep content changes reviewable and separate from deployment configuration; a content edit should not accidentally change the production secret set or adapter settings.
Summary
You now have a fast, Git-backed content site on Cloudflare’s edge. Edit in the repo or through the browser admin — every change is a real, reviewable commit. For a production site, make the build command, output directory, environment, and branch explicit so a preview cannot silently become a production deploy.
Comments
One comment per thread every 30 minutes · edits are unlimited.