How to Deploy a Static Site to Cloudflare Pages (Step by Step)
If you are paying for shared hosting to serve plain HTML, you are paying for a
control panel you do not use and a bandwidth cap you have to think about. A static
site on Cloudflare Pages costs nothing, serves from the edge, and deploys on every
git push.
Here is the whole setup. It takes about five minutes the first time.
What you need first
- A repository on GitHub or GitLab. Cloudflare builds from Git, so the code has to live somewhere it can reach.
- A Cloudflare account. The free plan is enough — the free tier includes unlimited bandwidth and 500 builds per month.
- Node.js 20.19.1+ or 22.12.0+ if you want to build locally before pushing.
That is it. No credit card, no server to patch.
Step 1 — Confirm the build output
Whatever framework you use, Cloudflare needs to know two things: the command that builds the site, and the folder that comes out the other end.
For Astro, that is npm run build producing dist/. Verify it locally first,
because a build that fails on Cloudflare wastes a deployment cycle:
npm install
npm run build
# dist/index.html should now exist
If dist/index.html is there, you are ready to push.
Step 2 — Push, then connect the repository
git add .
git commit -m "ready for deploy"
git push origin main
Then in the Cloudflare dashboard: Workers & Pages → Create → Pages → Connect to Git, authorise GitHub, and pick the repository. Cloudflare pre-fills build settings when it recognises the framework. Confirm they match:
| Setting | Value |
|---|---|
| Framework preset | Astro (or your framework) |
| Build command | npm run build |
| Build output directory | dist |
| Production branch | main |
Every push to main now triggers a production deploy. Pull requests get their own
preview URL automatically, which is genuinely useful for reviewing layout changes
on a real device before they go live.
Step 3 — Point your domain at it
Add the domain under Custom domains. If the domain’s DNS is already on Cloudflare, it connects in seconds and the certificate is provisioned for you. If the DNS lives elsewhere, Cloudflare will give you nameservers to switch to, which takes a few hours to propagate.
Step 4 — The four settings that break things later
This is the part most guides skip, and it is where people lose money quietly.
1. Turn Rocket Loader off. Under Speed → Settings → Content Optimization. Rocket Loader rewrites how JavaScript loads on your pages. That is fine for a plain blog and fatal for ad scripts and analytics verification — the script simply never runs, and nothing in any dashboard tells you why.
2. Turn Bot Fight Mode off. It will challenge or block the automated crawlers that ad networks use to review your site and verify your traffic. The visible symptom is an application that “just never gets reviewed”.
3. Auto Minify is deprecated, and a legacy zone can still have it on. Cloudflare’s
documentation now only covers turning Auto Minify off, and only through the API —
there is no dashboard switch for it any more. Aggressive HTML minification can break
inline scripts, so if your ad units render blank on a zone that predates the change,
check /zones/{zone_id}/settings/minify before you look anywhere else.
4. Do not add a Content-Security-Policy header yet. Ad network scripts load from a shifting list of third-party domains. A CSP that does not list every one of them will silently blank your ads. Add one only when you are ready to enumerate every domain.
What this costs
| Item | Cost |
|---|---|
| Cloudflare Pages (static) | $0 |
| Bandwidth | $0 — unlimited on the free plan |
| Builds | 500/month free |
| SSL certificate | Automatic |
| Domain | ~$10/year at cost price |
The only recurring cost is the domain. That is the whole bill.
When this is the wrong choice
Static hosting on Pages is the wrong call if you need server-side sessions, a database on the same origin, or anything that must run per-request without an edge runtime. You can add Workers for that, but at that point you are running an application, not a static site, and the deployment model deserves a separate decision.
For a content site — which is what most people actually need — static is faster, cheaper and has fewer moving parts. There is nothing to patch and nothing to restart.
Two things that come up within the first month, and that are not really Cloudflare problems: the redirects and headers files you will want the moment a URL changes, and environment variables, which do not behave on a static site the way they do on a server — anything the build can read, the visitor can read too.
Sources
Primary documentation only — the provider's own page, the specification, or the standard itself. Claims that rest on anything else are described in the text as a market pattern or an inference, not as documentation.
- Cloudflare Pages — Limits (500 builds per month and 20,000 files on the Free plan)
- Cloudflare Pages — Build configuration (build command and output directory)
- Cloudflare Pages — Custom domains
- Cloudflare Pages — Preview deployments
- Cloudflare Pages — product page (unlimited bandwidth and requests on all plans)
- Cloudflare — Rocket Loader
- Cloudflare — Bot Fight Mode
- Cloudflare — Turn off Auto Minify via API (the only documented path, because the feature is deprecated)
Written by Sam Wang. Spotted something out of date? Tell us.