Controlling Cloudflare costs with caps

Usage-based billing has no brakes. A Worker scales to whatever shows up, which is the whole point — right up until what shows up is a Worker fetching a URL that routes back to itself, or a scraper that found your endpoint, or * * * * * where you meant 0 * * * *. Nothing errors. Nothing crashes. The request count just climbs, and the first thing that tells you is the invoice.

Cloudflare has closed part of this gap. Since April there is a Billable Usage dashboard under Manage Account → Billing, fed by the same system that generates the invoice, so the daily numbers actually match the bill. Alongside it are budget alerts: set a dollar threshold and you get an email when your projected monthly spend crosses it, calculated daily, once per billing cycle, on pay-as-you-go accounts. Both are genuinely useful and you should turn them on.

Neither one stops anything. That is the distinction worth being clear about: an alert is a smoke detector, and what you want at 3am is a sprinkler. The one native control that does bound something is the per-invocation CPU limit — limits.cpu_ms in your Wrangler config, or Settings → CPU Limits in the dashboard. The docs recommend it against exactly this scenario, and it works, but it caps the CPU one request may burn. It has nothing to say about ten million of them.

So what does a cap have to do? Watch the month's spend, and when it crosses your number, take away the ways traffic reaches your code. Concretely that means disabling the workers.dev subdomain, detaching custom domains, removing routes in every zone, and clearing cron triggers — and writing each of those down before you remove it, so that resuming restores what was actually there rather than your best recollection of it. The script itself is never touched.

The uncomfortable part is measurement. There is no public endpoint for what do I owe right now, so a cap has to estimate: this month's requests and CPU time out of usage analytics, priced with the published Workers rates. That is close, but it is not your invoice, and a tool that pretends otherwise is lying to you. It also means a Workers-only cap says nothing about R2, D1 or KV, and that pulling the public entry points does not stop a service binding from another Worker, a Durable Object alarm, or a queue consumer.

A cap built on an estimate is a safety net, not a guarantee — and a safety net is still worth having, as long as it is honest about where its edges are. That is the trade I decided I wanted, so I built Controlflare to make it: a monthly cap per account, checked every five minutes, pausing Workers when the estimate crosses it and never resuming them on its own. Full disclosure, it is mine. It is free while it is in beta, and if handing an API token to someone else's dashboard is not your idea of cost control, the same Worker deploys into your own account instead.

back to the writings