Yangworks ran on Cloudflare Pages and a direct-upload project, and now runs on Workers Static Assets. That migration is the evidence behind this comparison, and it also fixes its limits: this was a static site with no Pages Functions, no bindings, and no server-side rendering. Everything below is scoped to that case, and the sections that go beyond it are labelled.
The short version: for a purely static site the two platforms are close enough that the decision is not about capability. It is about which set of defaults you want to be responsible for, and where Cloudflare is putting its future work.
Cloudflare's own position is not neutral
This is the one part of the comparison that does not require judgment, because Cloudflare stated it directly. In the post announcing full-stack support on Workers, Cloudflare wrote that you should start with Workers
, that Cloudflare Pages will continue to be supported
, and that going forward, all of our investment, optimizations, and feature work will be dedicated to improving Workers.
Read that carefully, because it says two different things. Pages is supported — it is not deprecated and it is not scheduled for removal. But Pages is also not where new capability is going to appear. Author judgment: that makes the choice for a new project easy and the choice for a working Pages project genuinely open, which is the opposite of how migration advice is usually written.
The configuration model is the real difference
Pages kept most of its behaviour in the dashboard and inferred the rest from your build output. Workers keeps it in a checked-in Wrangler file. Cloudflare's migration guide maps the keys:
Pages Workers
--------------------------- --------------------------------
pages_build_output_dir --> assets.directory
(compatibility date optional) compatibility_date (required)
ASSETS binding automatic --> assets.binding (declared)
Functions run first --> assets.run_worker_first
For Yangworks the entire Workers configuration is four lines of asset settings and no Worker script:
{
"name": "yangworks",
"compatibility_date": "2025-01-01",
"assets": {
"directory": "./public",
"not_found_handling": "404-page"
}
}
The Cloudflare docs note that if there is no Worker script you should drop the "binding": "ASSETS" entry, since it is only meaningful alongside main.
Inference becomes declaration
Pages inspected the output directory for 404.html and index.html and guessed whether you wanted single-page-application fallback or a custom not-found page. Workers requires not_found_handling to be set to either "single-page-application" or "404-page". The documentation explains why in one sentence: to prevent accidental misconfiguration, this behavior is explicit and must be set up manually.
The same pattern repeats elsewhere. Pages automatically excluded files such as node_modules, .DS_Store, and .git from upload; on Workers you reproduce that with an .assetsignore file inside the asset directory.
Author judgment: for a generated public/ directory that is rebuilt from scratch on every run, this trade is clearly favourable — the ignore list is empty and the 404 behaviour is now visible in a pull request instead of a settings screen. For a project whose output directory is also its working directory, it is extra bookkeeping.
Routing precedence flips
This is the change most likely to break a real application, and it did not affect Yangworks at all because there is no Worker code here. Cloudflare documents that Pages ran Functions ahead of static assets, tunable with _routes.json and middleware, while Workers will default to serving static assets ahead of your Worker script
. If you relied on middleware for authentication checks or request logging, you need run_worker_first to restore the old order. The docs also note that Pages middleware moved to Workers is charged as a normal Worker invocation.
Clean URLs and 404s behave the same, but you should verify them
Workers Static Assets normalizes URLs through html_handling, which defaults to auto-trailing-slash: individual files are served without a trailing slash, folder index files with one. Every redirect documented for that normalization is a 307, not a 301.
On the live Yangworks deployment, checked 7 August 2026, that matches: /handbook/niche.html returns 307 to /handbook/niche, and a route that does not exist returns a 404 status with the generated error page. Those two requests are worth making after any migration, because a friendly error page served as 200 OK is still a routing bug.
One compatibility detail that saves work: _headers and _redirects are, per Cloudflare's documentation, supported natively in Workers with static assets
— you keep the files where they were.
Git deployment and previews are close, not identical
Both platforms build from a connected repository. On Workers the flow is Workers Builds running your build command and then npx wrangler deploy; Yangworks uses npm run build and the production branch main.
Preview parity takes two settings rather than being automatic: Cloudflare's guide says to keep preview_urls enabled (it is on by default) and to turn on builds for non-production branches. Preview URLs can optionally be placed behind Cloudflare Access.
The migration guide is also explicit about a failure mode that Git history will not catch: after connecting Workers Builds, disable automatic deployments on the Pages project. Otherwise one repository quietly feeds two deployment systems while you believe the move is finished. Delete the Pages project only after traffic and routes are confirmed.
What Pages still does that Workers does not
All of these are from Cloudflare's own migration guide, which is unusually candid about the gaps:
- Custom domains on off-Cloudflare nameservers. Supported on Pages, unsupported on Workers. For anyone whose DNS is not on Cloudflare, this is a blocker rather than an inconvenience.
- Per-environment bindings. Workers cannot define different bindings for production and non-production builds; the workaround is Wrangler Environments plus build configuration. Cloudflare says this is
something we are actively exploring.
- Custom Branch Aliases are marked coming soon, and Branch Deploy Controls are only partially matched.
- Early Hints is a workaround (zone setting plus
Linkheaders) rather than a feature. - File-based routing and Pages Plugins require either framework support or compiling the
functions/directory yourself.
What Workers does that Pages does not
The same guide lists the other direction: the Vite plugin, gradual deployments, remote development, Workers Logs, Logpush, Tail Workers, source maps, Cron Triggers, Queue Consumers, Rate Limiting, Email Workers, Image Resizing, non-root routes, and serving assets on a path. Durable Objects are usable directly rather than through a separate Worker.
Author judgment: none of that list matters to a static publication today. It matters a great deal to the version of the project that eventually needs a login, a scheduled job, or an API route — and that is the argument for moving before you need them, not after.
Cost and limits
Cloudflare's pricing page states that Requests to static assets are free and unlimited
, and that storing assets carries no additional cost. The Workers Free plan allows 100,000 requests per day; Workers Paid starts at $5 per month with 10 million requests included. Platform limits for static assets are 20,000 files per Worker version on Free and 100,000 on Paid, with a 25 MiB maximum for an individual file.
One free-tier caveat is worth knowing before enabling run_worker_first: matching requests always invoke the Worker, and once free-tier request limits are exceeded those requests receive a 429 rather than falling back to static asset serving.
This article measures no cost difference between the two platforms. Yangworks did not run both in parallel, did not record bills, and does not claim savings.
The migration order that worked here
The sequence that made this readable was to change one thing at a time. Source consolidation first: one repository, one npm run build, one public/ artifact. Then the deployment: add wrangler.jsonc, connect Workers Builds, verify, disable and remove the old projects. Language expansion came later and changed only the contents of public/, not the number of deployments. The commit-level account is in the migration field note, and the resulting build and deployment contract is described in the deploy guide.
The step that is easiest to skip and most expensive to skip is writing down the expected status code and final URL for every route before cutover — .html forms, trailing slashes, language roots, and any legacy host — then checking them against the deployed responses rather than against a browser's address bar.
Which one to choose
The following is author judgment, not Cloudflare guidance.
Start on Workers if the project is new, if you want the deployment contract in version control, or if you can foresee needing scheduled jobs, queues, logs, or an API path alongside the static files.
Stay on Pages if it is working, if your nameservers are not on Cloudflare, if you depend on per-environment bindings or Pages Plugins, or if your team's review process assumes branch-alias behaviour that Workers has not matched yet. "Supported" is a real commitment, and a migration you do not need is still a migration you have to verify.
What this comparison does not establish
One site, one migration, no Functions, no bindings, no SSR. No performance benchmark was run, no build times were compared, no bills were compared, and no availability difference was observed or claimed. A team migrating a full-stack Pages application with middleware and per-environment bindings is facing a materially harder job than the one documented here, and should treat the gap list above as the starting point rather than the footnote.