Hosting Guide
Host a Static Site on Cloudflare Workers Static Assets
A folder of HTML plus two small files is all it takes to serve a site from Cloudflare's edge, with a www redirect and a real 404 page. This guide gives you both files and explains each line.
- Year 1Website
- Year 2Map Listings
- Year 3Booking Tool
- Year 4Front Desk
- Year 5Payments
- Year 6Reports
Same six pieces.
Years of lessons, one read.
Free to read. Most of this guide is open. The finishing pieces at the end come to you when you opt in.
The Short Version
- Workers static assets serves your built folder from Cloudflare's edge, and asset requests cost nothing on the free plan.
- One wrangler.jsonc file sets the folder, the 404 page, trailing slashes and your domains.
- A worker.js of about ten lines sends www to the bare domain and hands everything else to the assets.
- The free plan caps a site at 20,000 files, so count before you deploy a big directory.
Why Workers Static Assets
A local business site is mostly HTML, CSS and images. It does not need a server that runs all day. It needs files that load fast on a phone in a parking lot. Cloudflare Workers static assets does that. You upload a folder. Cloudflare copies it to its edge and serves each file from a spot close to the visitor.
You also get a small bit of code in front of the files when you want it. That is where a www redirect, a header or a health check lives. You do not need a second service for any of it.
This guide uses example.com. Swap in your own domain. The domain must already be a zone in your Cloudflare account, with Cloudflare as its nameserver.
The Folder You Deploy
Keep the Worker files at the top and the built site in its own folder. Your generator writes into public. You never edit files in there by hand.
example-site/
wrangler.jsonc
worker.js
package.json
public/
index.html
404.html
about/index.html
services/brakes/index.html
img/hero.webp
sitemap.xml
robots.txtGive every page its own folder with an index.html inside. Then /about/ is a real address and not a file name. That matches how the trailing slash setting below works.
The Wrangler Config File
This one file tells Cloudflare what to upload and how to serve it.
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "example-site",
"main": "worker.js",
"compatibility_date": "2026-09-01",
"assets": {
"directory": "./public",
"binding": "ASSETS",
"not_found_handling": "404-page",
"html_handling": "auto-trailing-slash",
"run_worker_first": true
},
"routes": [
{ "pattern": "example.com", "custom_domain": true },
{ "pattern": "www.example.com", "custom_domain": true }
]
}Here is what each setting does.
- main points to the Worker script that runs first.
- assets.directory is the folder to upload. Everything inside it becomes public.
- assets.binding names the handle your code uses to reach the files. Here it is
env.ASSETS. - not_found_handling set to
404-pageserves your nearest404.htmlwith a real 404 status. Without it, a missing page returns a bare 404 with no page. - html_handling set to
auto-trailing-slashsends/aboutto/about/when the page is a folder. Each page then has one address, which search engines like. - run_worker_first set to true sends every request through your script before the files. You need that for the www check.
- routes with
custom_domain: trueties the Worker to each hostname. Cloudflare makes the DNS record and the certificate for you.
Set compatibility_date to the day you start. Leave it alone after that unless you mean to pick up new runtime behavior.
The Worker Script
The script has one job before it gets out of the way. If the request came in on www, send it to the bare domain with a permanent redirect. Keep the path and the query string. Otherwise pass the request to the files.
// worker.js: send www to the bare domain, then serve the built files.
export default {
async fetch(request, env) {
const url = new URL(request.url)
if (url.hostname === 'www.example.com') {
url.hostname = 'example.com'
return Response.redirect(url.toString(), 301)
}
return env.ASSETS.fetch(request)
},
}env.ASSETS.fetch(request) does the rest. It finds the file, applies the trailing slash rule, sets the content type and serves your 404 page when nothing matches. You do not write any of that yourself.
Pick one home for the site and stick to it. This guide picks the bare domain. If you pick www, flip the check. What matters is that only one version answers with a 200.
Deploy It
Install Wrangler in the project, sign in once, test locally, then deploy.
npm install --save-dev wrangler
npx wrangler login
npx wrangler dev # test on your own machine first
npx wrangler deploy # publish to example.com and www.example.comThe first deploy creates both custom domains. If a hostname already has an A or CNAME record in the zone, the deploy stops and tells you. Delete the old record in the Cloudflare dashboard and deploy again. Cloudflare then makes its own record for the Worker.
A deploy takes seconds. There is no build minute to pay for, because you build on your own machine or in your own CI. The upload only sends files that changed.
Limits to Know Before You Start
The free plan allows 20,000 files per Worker. A small business site will never get close. A directory site with a page per listing and a few images per page can pass it fast. Count the files in public before you deploy. The paid plan raises the cap a great deal.
Each file can be up to 25 MiB. Large videos belong somewhere else, such as a video host or object storage.
With run_worker_first on, every request counts as a Worker call. Asset requests that skip the script are free and unlimited. If you ever get near the free daily limit, move the www redirect to a Cloudflare Redirect Rule and set run_worker_first to false. Then the script runs only when no file matches.
What Happens on Each Request
It helps to picture one visit from start to end. A customer taps a link to www.example.com/services/brakes on their phone.
- The request lands at the Cloudflare site closest to them. Cloudflare holds the certificate, so the secure connection is set up right there.
- Your Worker runs first. It sees the www and returns a 301 to
example.com/services/brakes. The phone follows it. - The second request reaches the Worker again. The host is right, so it calls
env.ASSETS.fetch. - The assets layer sees there is a folder named
brakeswith anindex.html. It sends a redirect to the address with a slash on the end. - The third request finds the file and returns it with a 200.
That is two redirects for one tap. Search engines and phones handle it fine, but it is waste. Link to the final address everywhere you can. Use the bare domain and a trailing slash in your menus, your sitemap, your Google Business Profile and your ads. Then most visits take one hop.
Build Into the Folder, Not Onto It
The files in public should come from a build step, even a small one. A script that turns page data into HTML is enough. The rule is simple. If a page is wrong, fix the script or the data and build again. Do not open the HTML and patch it. The next build will wipe the patch, and you will not notice until a customer does.
Clean the folder at the start of each build. Old pages you deleted from the data will otherwise stay live forever, because the deploy uploads whatever is in the folder. A stale page with an old price is worse than no page.
Have the build also write the sitemap, the 404.html page and robots.txt. Then the list of pages the site has and the list it tells Google about come from one place and cannot drift apart.
What the Finishing Pieces Contain
With the two files above, your site is live on your domain with a www redirect and a real 404 page. The finishing pieces cover the rest of a launch. You get a copy ready _headers file for security and cache rules, a _redirects file for moving an old site without losing its links, a Worker that adds headers and a health check, and the command list we run to prove a launch is right. Enter your email to open them. When the site is live, set up Search Console and IndexNow next.
The finishing pieces
Get the Rest of This Guide
You have the method. The finishing pieces are the parts you copy straight into your own work:
- Copy Ready Headers File
- Moving an Old Site Without Losing Links
- The Edge Cases That Bite
- Test the Real Thing Before It Is Live
- The Launch Check
Questions People Ask
Is Cloudflare Workers hosting free for a small business site?
For most small sites, yes. Requests for static files are free on the free plan. Worker calls have a daily limit that a local business site rarely comes close to.
Do I need Cloudflare Pages for this?
No. Workers static assets serves a folder of files the same way, and it lets you add code in front of them when you need it.
Should my site use www or not?
Either works. Pick one, redirect the other to it with a 301, and use the same one in every canonical tag and sitemap.
What happens if my site has more than 20,000 files?
The deploy fails on the free plan. Move to the paid plan, which allows far more files, or cut down the files you ship.
We sell time
Get Years of Building Switched On in Hours
A thirty minute call. A written price. Nothing built until you say yes.