What the Cloudflare Workers Move Actually Cost Us, Measured
webdevelopment October 21, 2026 · Mintec

What the Cloudflare Workers Move Actually Cost Us, Measured

We moved mintec.co from Cloudflare Pages to Workers and measured the bill: build time, artifact size, TTFB per request path, and a Lighthouse run. Every number carries its tool, date and URL.

The move from Cloudflare Pages to Workers cost mintec.co nothing measurable in delivery performance, and bought us five times the file headroom before we hit a hard platform limit. That is the headline of our own ledger, measured on our production deployment on October 21, 2026 — and the interesting part is not the number, it is that almost nobody publishes this kind of ledger. The week we moved, our Cloudflare/Workers cluster was pulling 3,477 impressions a month in Search Console at click-through rates between 0.2% and 1.1%. People are asking whether to move. They are not being shown what a move costs once somebody has actually done it.

So here is ours, with the tool, the date and the URL behind every figure.

Why "what changed" coverage is not enough

We published the decision framework for the Pages-to-Workers move when Cloudflare's own docs started opening by asking whether you were sure you wanted Pages. We covered Node.js compatibility turning on by default for every Worker. We compared Astro and Next.js with real benchmarks. All of that answers what changed. None of it answers the question a technical buyer actually has to take into a budget meeting: what does this cost me, in what dimension, and where does it show up?

A migration has four cost dimensions. If you can fill in all four with numbers, you can defend the decision. If you can only fill in "the docs changed", you are guessing.

Cost dimensionWhat it measuresWho feels it
ToolchainBuild wall-clock, peak memory, CI container limitsEngineers, every commit
ArtifactFiles and bytes per deployment against the platform capWhoever hits the limit at 2 a.m.
Request pathTime to first byte, per request classEvery visitor and every crawler
Field performanceCore Web Vitals in the browserConversion, rankings, patience

The measured ledger

Every row below was taken on our own production site, mintec.co, on October 21, 2026. The "before" column comes from our Lighthouse-based site audit of 50 pages, run on October 19 — the last crawl before the cutover landed on October 20.

MetricBefore (Pages, Oct 19)After (Workers, Oct 21)What caused the delta
Deployment file cap20,000 files, hard platform limit100,000 static files per WorkerCloudflare's documented limits for each product
Deployed file count~21.7k files counted Oct 2021,733 files in dist/Two new articles and their pages; nothing structural
Build wall-clocknot recorded~15 min on a 4-vCPU boxAstro static build of the full site, same machine
Server response, median139 ms across 50 crawled pages137 ms homepage / 212 ms deep page (curl, same box)Same static bytes, different delivery path
Lab TTFB (Lighthouse)not recorded278 msThrottled mobile lab run, not a field value
Lighthouse performancenot recorded62Third-party JavaScript, not hosting

Read that table again and notice what is missing: a performance improvement. There is none, and that is the finding. The static output on both platforms comes out of the same dist/ — our parity check exists precisely to prove that a served page is byte-identical to its build output apart from the injected analytics beacon. A migration that changes where bytes are served from, and not the bytes, should not move Core Web Vitals. If yours does, something else in the pipeline changed at the same time, and you now have two variables and one incident.

The artifact dimension: the real reason we moved

The file cap is the only line in that ledger with a hard cliff. Cloudflare Pages caps a deployment at 20,000 files. Workers static assets allow 100,000 files per Worker on a paid plan. Our build sat at roughly 21,000 files and was growing by thousands of location and service pages a month. On Pages, we were past the limit and managing around it. On Workers, we have years of headroom at the current growth rate, and the repo now carries a build step that warns from 80,000 files and stops the deploy at 99,000, so the limit announces itself in a pull request instead of an outage.

That is the honest cost-benefit ratio: you do not move for speed. You move when a documented platform limit becomes the thing standing between you and next quarter's content plan.

The request path: what a Worker in front of everything actually costs

Here is the architectural difference that deserves a number. On Workers, run_worker_first is set so our Worker runs before static assets on every path except the asset prefixes — /_astro/, /images/, favicons, robots.txt, llms.txt, rss.xml and the sitemaps. Those skip the Worker entirely. Every HTML page, every redirect, every API route invokes it.

So the fair question is: what is the measured price of that invocation? We measured it the only honest way available from one machine — by comparing the two request classes from the same box, minutes apart, with Cloudflare cache status recorded on every sample.

Request classSamplesMedian TTFBCache status
HTML, homepage (/)3137 msHIT
HTML, deep blog post6212 msHIT
HTML, cache-busted /about/3231 msHIT
CSS asset, skips the Worker6151 msHIT
JavaScript asset, skips the Worker3187 msHIT
Image asset, skips the Worker3205 msHIT

The Worker-handled HTML sits roughly 60 ms above the Worker-skipping CSS at the same edge, both from cache. Treat that as an upper bound on the invocation overhead we can see from a single vantage point — it is not a controlled A/B, the payloads differ, and one datacenter curl is not a field study. What it does tell you is the order of magnitude: the runtime layer is not where your milliseconds are going.

One nuance worth stealing: on Pages, our function middleware already saw essentially every HTML request. The per-request execution was never free — it was just accounted differently. If you are moving off a platform that already ran server code per request, do not budget for a new cost class. Budget for the audit that confirms which paths still hit it.

The toolchain dimension: where the speedup actually landed

Cloudflare announced tsrs, its Rust port of the TypeScript compiler, built with VoidZero on October 20 — up to 8× faster and about 70% less memory than TypeScript 7.0 at the same number of type-check workers, feeding into the Oxc toolchain rather than forking TypeScript.

That is a genuine engineering feat and it will land in your build minutes, not in your LCP. A faster compiler changes your edit loop. It changes your users' experience only if it changes the bytes you ship, the code on the request path, or the work in the browser. This is the single most common category error we see in migration pitches.

Our own toolchain constraint was memory, not CPU: the commit on our main branch dated October 21 caps Astro's heap at 2,560 MB so the Cloudflare build container stops running out of room. That is the kind of number that never appears in a vendor benchmark and always appears in your incident channel.

How we price a framework decision now

The framework is four lines, and the discipline is that every line needs a tool, a date and a URL:

  1. Toolchain — wall-clock of the production build, peak memory, and the container limit it has to fit inside. Measure it on the same machine you will build on.
  2. Artifact — files and bytes in the output directory, next to the platform's documented cap. Headroom in months, not in percentages.
  3. Request path — median time to first byte per request class, with cache status on every sample, from one fixed vantage point.
  4. Field performance — Core Web Vitals before and after, from a lab run you control and, when you have the traffic, field data you do not.

If a vendor or a benchmark cannot fill in all four, it is selling you a dimension, not a decision. That is also how we decide which layers of the stack to adopt and which to keep portable — the measurement has to survive the pitch.

None of this is a reason to postpone a build. It is a reason to record your numbers before you change the variable, so that when someone asks what the move cost, you answer with a ledger instead of an adjective. If you are staring at a similar decision and want a second read on the numbers before you commit, that is the conversation we have with clients — start here.

Frequently Asked Questions

Does a faster TypeScript compiler or a new runtime port speed up my product?

No, not by itself. A toolchain change speeds up your build and your edit loop. It only reaches your users if it changes the bytes you ship, the code that runs on the request path, or the rendering work in the browser. Measure those three separately, or you will credit the compiler for work it never did.

What actually moves Core Web Vitals on a static marketing site?

Not the host. On a prerendered site the host decides cache behavior and time to first byte, and that is usually already inside the budget. What moves Core Web Vitals is third-party JavaScript: script count, main-thread work, and the image payload. On our own homepage, 45 script requests account for 5.8 seconds of the 9.7 seconds of main-thread work Lighthouse records.

Related Articles