← Back to blog Khalil Drissi

How to deploy a static site to Cloudflare Pages

Listen to article
0:00

I have shipped a lot of sites onto Cloudflare Pages, including the one you are reading right now. The reason I keep coming back is boring in the best way: it is fast, the free tier is generous, and once it is set up I rarely think about it again. Here is how I do it.

Connect the repository first

Pages is happiest when it builds from a Git repo. Sign in to the Cloudflare dashboard, open Workers and Pages, and pick “Create application” then “Pages”. Authorize GitHub or GitLab, select your repository, and you land on the build configuration screen. This is the part people get wrong, so slow down here.

You need three things: the framework preset (or “None” for a hand-rolled build), the build command, and the output directory. For my own generator the build command is node build.js and the output directory is dist. If you are using a known tool, the presets fill these in for you. If your “build” is just copying files, set the command to something harmless like echo done and point the output at your folder.

Match the Node version to your local one

A surprising number of failed first deploys come down to Node mismatches. Pages defaults to a recent Node, but your code might assume something else. I pin it explicitly with an environment variable so there are no surprises:

NODE_VERSION = 20.11.0

Add that under Settings, Environment variables, for both Production and Preview. While you are there, add any other secrets your build needs, like API tokens for pulling content. Anything sensitive belongs here, never in the repo.

Trigger the first build

Hit “Save and Deploy” and watch the log stream. The first build is the honest one. If a dependency is missing or your output directory is wrong, you will see it immediately. A clean build ends with Pages uploading your files to its edge network, and you get a *.pages.dev URL to test against. Open it, click around, and confirm assets actually load. Broken relative paths are the most common issue, usually from a site that assumed it lived at a subpath.

Add your custom domain

Once the preview looks right, attach a real domain. Go to the project’s Custom domains tab and add your hostname. If the domain is already on Cloudflare, the DNS record is created for you in one click. If it lives elsewhere, you will get a CNAME to add at your registrar. Propagation is usually minutes, not hours. Cloudflare provisions the TLS certificate automatically, so HTTPS just works without you touching certbot.

Set up redirects and headers

Static sites still need rules. Pages reads two special files from your output directory. A _redirects file handles URL rewrites and old links, and a _headers file lets you set caching and security headers. Here is a small example that locks down framing and caches assets hard:

/*
  X-Frame-Options: DENY
  Referrer-Policy: strict-origin-when-cross-origin

/assets/*
  Cache-Control: public, max-age=31536000, immutable

Drop those in the folder you ship, not the project root, unless your build copies them across. Aggressive caching on hashed asset filenames is one of the cheapest performance wins you will ever get.

Automate redeploys

Every push to your production branch triggers a fresh build, and pull requests get their own preview URLs automatically. That alone covers most workflows. But if your content lives outside the repo, in a CMS for example, you will want a build hook. Create one under Settings, Builds and deployments, and you get a URL you can POST to from anywhere to kick off a deploy. I wire mine to a webhook so editors never touch Git.

If you want more control over the build pipeline, you can skip the dashboard build entirely and run it yourself. I cover that approach in setting up CI/CD with GitHub Actions, which lets you deploy with the Wrangler CLI after your own test and lint steps pass.

What I check before calling it done

Before I trust a deploy, I run through a short list. Does the custom domain serve over HTTPS with no mixed-content warnings? Do the redirects actually fire? Are large images sensible, or am I shipping 4MB hero photos? That last one matters more than people expect, and I wrote up my whole approach in optimizing images for the web.

That is genuinely it. Cloudflare Pages rewards a simple setup, and the edge network means your visitors in Sydney get the same snappy load as the ones next door. Once the pipeline is in place, deploying becomes a non-event, which is exactly what you want.

Comments
Leave a comment