For assets only, omit both main and the assets binding. Use 404-page for a content site and single-page-application only when a client-side router must receive unmatched application routes.
1. Use the assets-only configuration
Cloudflare Workers can deploy HTML, CSS, JavaScript, fonts, and images without a JavaScript Worker. Wrangler uploads the directory named by assets.directory, and Cloudflare caches matching files across its network.
Cloudflare’s static-assets documentation says that, without a script, a missing asset returns 404 unless you select another not_found_handling mode. This fits hand-written HTML, a documentation site, or the output of a static-site generator.
Install the current Wrangler release, then create wrangler.jsonc. The example assumes deploy-ready files are in public/ and that the site has a real 404.html. There is no main because there is no Worker script.
npm install --save-dev wrangler@latest{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "my-static-site",
"compatibility_date": "2026-10-20",
"assets": {
"directory": "./public",
"not_found_handling": "404-page"
}
}There is no assets binding either. Cloudflare’s Pages-to-Workers migration guide says an assets binding is valid only when a script is declared by main. Set the compatibility date to the date you create or intentionally update the project, then test the change.
2. Choose 404-page or SPA routing
Use 404-page for multi-page or generated HTML. A missing URL receives HTTP 404 with the nearest 404.html. That matters to users, monitoring, and search engines: an error page returned with HTTP 200 is a soft 404. Put a root 404.html in the asset directory and test a path that has never existed.
Use single-page-application when a client-side router must receive unmatched application routes. Cloudflare returns index.html with HTTP 200 for those paths. Your app still needs a visible not-found route for unknown client routes. Do not use SPA fallback merely to hide broken links on a content site.
Add main and an assets binding only when you need code. By default, a matching asset is served before the Worker. An unmatched request reaches the script. Set run_worker_first to selected paths, such as /api/*, when those routes must always execute code.
3. Add redirects and headers
Workers static assets support the same plain-text _redirects and _headers files used by Pages. Keep them inside the asset directory. They are parsed as configuration and are not served as downloadable files.
# public/_redirects
/old-page /new-page/ 301
/about /about/ 301# public/_headers
/*
X-Content-Type-Options: nosniff
/assets/*
Cache-Control: public, max-age=31536000, immutableRedirects run before header rules. Cloudflare’s redirect documentation allows 2,000 static and 100 dynamic rules. If several rules match the same source, the top rule is applied, and the default status is 302 when you omit the code.
The headers documentation warns that _headers does not affect responses generated by Worker code. Add those headers in the script itself. Limit long cache lifetimes to files whose names change when their content changes.
4. Run locally, deploy, and verify HTTP
npx wrangler dev
npx wrangler deployOpen the home page, a nested page, a static asset, a redirect source, and a nonexistent path. Check status, Location, Content-Type, and cache headers—not just what the browser renders.
When the project has workers_dev enabled, the deployment is available on a workers.dev URL. A custom domain is a separate routing and DNS step. Cloudflare’s migration guide says custom domains require nameservers managed by Cloudflare.
For a generated site, run its build before Wrangler so assets.directory contains the final files. A successful upload proves files were deployed. It does not prove canonical URLs, redirects, forms, or client-side routes behave correctly.
5. Frequently asked questions
Do I need a Worker JavaScript file?
No. An assets-only project needs a name, compatibility date, and assets directory. Omit main and the assets binding. Add a script when you need an API, authentication, HTML transformation, or another dynamic response.
Should I use SPA or 404-page handling?
Use SPA handling for a client-side router whose valid routes do not correspond to files. Use 404-page for a multi-page content site. The latter returns a real HTTP 404 with the nearest 404 page.
Are static asset requests billed as Worker invocations?
Cloudflare’s migration guide says requests for static assets are free. If a request invokes Worker code, Worker pricing applies. Check the current pricing and limits page for the account and date of your deployment.
6. Related articles and next steps
Before publishing, check the production build, redirects, response headers, and a real missing-page response.
Continue learning
Tell us the build output, routing model, custom domain, and any server-side routes you need. Email OdooMatrix to discuss the next step.