Studio · Est. 2009 · Web + Software + Frameworks RSS · Start a Project →
Web Development
Article · Web Development

Deploying Static Sites to Cloudflare Pages in 2026: A Pragmatic Guide

Date · 18 April, 2026
Read · 3 min

Cloudflare Pages is now our default static host. It has been for about eighteen months. The tooling settled, the edge story matured, and the price for serious traffic is still — improbably — zero. This is the workflow we use for production sites in 2026, distilled down to what matters.

The minimum viable deploy

If your output is a folder of static files (it usually is), the entire deploy is one command:

npx wrangler pages deploy ./dist --project-name=your-project

The first time it runs, Wrangler creates the project. Every subsequent run uploads a new immutable deployment, gives you a unique preview URL, and atomically swaps production once you confirm. No build pipeline, no GitHub Actions, no waiting in a queue.

Project structure that does not fight you

We keep this layout for every Pages project:

  • /site/ — the actual output, what gets deployed
  • /_headers — global response headers (cache, security)
  • /_redirects — old URL → new URL mappings
  • /functions/ — optional edge functions (kept empty unless needed)
  • /redeploy.sh — one script that rebuilds and deploys

The principle: a junior teammate should be able to ship a fix to production by running one command they did not have to write.

Headers worth setting

Out of the box, Pages serves files with reasonable defaults. We override two categories:

Long-lived assets

/*.css
  Cache-Control: public, max-age=31536000, immutable
/*.svg
  Cache-Control: public, max-age=31536000, immutable

Anything content-hashed gets a year. Pages handles invalidation by serving new hashes on the next deploy.

HTML

/*.html
  Cache-Control: public, max-age=0, must-revalidate

HTML is always re-validated. The CDN still caches it, but stale-while-revalidate keeps users on the latest deploy without us touching anything.

Redirects: the only WordPress-era debt worth paying off

If you're moving a legacy site (we do this often), preserve URLs religiously. Pages reads _redirects in Netlify format. One line per redirect, glob patterns are allowed:

/old-blog/* /blog/:splat 301
/feed/ /feed.xml 301
/wp-content/* / 404

Run the redirects through a check before deploying — broken redirects look the same as working ones until somebody links to one.

Custom domains, briefly

Add the domain in the Pages dashboard. If the domain is already on Cloudflare, DNS is automatic — Pages picks the right CNAME for you. If it isn't, you'll get the records to add. SSL is free, renews itself, and the certificate is issued before the page reloads.

The thing that still trips people up: www. vs apex. Decide which one is canonical, set up a redirect for the other, and put the right one in your sitemap. Pages will happily serve both, but Google does not love seeing duplicates.

Edge functions: use them sparingly

Pages Functions are a flat /functions/ directory of route handlers. They run on Workers, billed at Workers prices, and there is no cold start to worry about. The 2026 advice: if you can avoid them, do. Every function is something else to test, monitor, and reason about. Reach for them only when:

  • You need per-request data (geo, headers, cookies) that must be on the edge.
  • You're proxying or rewriting before serving static content.
  • You have one specific dynamic endpoint and you don't want a whole API.

Things that surprised us this year

Deploy speed. Even on a 5,000-file site, a fresh deploy completes in under a minute. The diff-uploading is doing real work.

Preview URLs are first-class. Every deploy gets one. We send those links to clients for sign-off without anyone learning what "staging" means.

Wrangler quirks. The --commit-message flag is useful — those messages show up in the Pages dashboard. We populate it with a timestamp and the commit hash, which makes rollbacks much less guesswork.

Where this falls down

Pages is not a CMS. If your content team needs a click-through publishing flow, you need a CMS in front of Pages — we usually pair it with a headless one and a webhook that triggers redeploy.sh. The split adds complexity worth thinking about before committing.

And for genuinely dynamic apps — auth-heavy, database-heavy, server-state-heavy — Pages is the wrong shape. Reach for Workers proper, or somebody else's platform.

For everything in between, the answer is still: ship the folder, walk away, do something else.