Neither juudd plan counts requests. Not the free one, not the $12-a-month one, and neither counts bandwidth either.
That is the whole of the pricing decision as it touches traffic. What follows is the reasoning that forced it, what we found when we checked whether we could afford it, and the one part of it we are still inferring rather than measuring.
A meter you cannot control is a bill you cannot explain
Requests were the first meter we considered, and rejecting them was a product decision rather than an arithmetic one. A bot or a curl flood spikes request count and the customer is billed for traffic they did not want and cannot prevent. An unexplainable bill is the outcome a request meter produces on exactly the day the customer is least able to do anything about it.
You cannot prevent it because the traffic does not arrive through you. It arrives at the edge, at a hostname, from an address neither of us chose. A meter that bills you for the behaviour of strangers is a meter that turns a bad morning into an invoice.
Bandwidth is the intuitive meter, and we do not buy any
Bandwidth is the meter people expect next, and it is intuitive and wrong: this platform does not pay for bandwidth. Three separate things have to be true for that sentence to hold, and all three are.
| what we buy | what it is billed on |
|---|---|
| the edge | requests, not transfer |
| the serving chain | dispatch → customer → outbound, billed as one request |
| the database | 500 GB of egress per project included, against 0.047 MB measured |
Charging for bandwidth would be charging for something we do not buy. That is not restraint; it is just refusing to invent a cost and pass it on.
From those two rejections one rule falls out, and we would rather state it as part of the price than keep it as a support policy: traffic the customer did not cause is ours to absorb. A policy is something you have to appeal to. A price is something you can read before you sign up.
One question killed the free quota
The free plan nearly shipped with a quota of 100,000 requests a month. It was killed by a single question from the owner:
If a free customer's site is hit by a bot, do we count it against them?
The answer has to be no. Once it is no, the quota has nothing left to do, since counting was the only thing it was for. Two further reasons are worth stating out loud.
The first is that a free tier which counted a bot flood would be stricter with people who pay nothing than with people who pay. We had just promised to absorb uncaused traffic on the paid plan. Metering it on the free one would have made the promise conditional on the invoice.
The second is that the numbers do not justify it. At $0.30 per million requests, a free site running ten times over such a quota costs us $0.30. Serving a 402 to a site that did nothing wrong, to save thirty cents, is the wrong trade, and the person who sees that page is not the site's owner but whoever happened to visit.
So the plans are bounded only by the things that actually cost money — a database project and a hostname at the edge — and by nothing else.
| plan | sites | database and custom domain | requests counted |
|---|---|---|---|
| free | two | no | no |
| $12 a month | ten | yes | no |
We did not invent this objection
On 8 September 2026, Vercel announced flat-rate CDN pricing, and described the problem in its own words:
viral launches, traffic bursts, or misconfigured routes sometimes turned an otherwise normal month into an unexpected bill.
Under that arrangement, CDN requests and data transfer are "no longer billed directly, so spikes don't result in surprise bills." Cloudflare, whose platform we run on, publishes that "There are no additional charges for data transfer (egress) or throughput (bandwidth)."
So the objection is not ours, and we should not pretend it is. It is recognised, in writing, by vendors who sell the infrastructure underneath it.
What we are saying is narrower, and worth stating exactly. The largest vendor in this category reached for flat rates on one resource after metering it. We chose not to install the meter in the first place. That is a difference in sequence rather than a claim to virtue, and the reason it is worth writing down is that a meter removed and a meter never fitted feel identical on a quiet month and different on a loud one.
We assumed serving static files cost us nothing, then we checked
The assumption underneath all of this was that a site of files is free to serve, because Cloudflare publishes that requests to static assets are free and unlimited. We had leaned on that sentence without testing whether it described us. On 2026-09-01 we tested it.
A files-only site was deployed and sixty requests were fired at it, thirty to / and thirty to a file, each one carrying a unique query string and cache-control: no-cache so the edge could not answer from cache. Then we read Cloudflare's GraphQL analytics for the seconds either side of the burst.
Our own dispatch Worker recorded sixty requests. The customer's own site script recorded none at all. Sixty requests in, sixty dispatch invocations out, exact.
The absence needed a control, because a dataset that reports nothing looks the same as a script that ran nothing. An earlier read of that same dataset had listed a different namespace script with three requests. The dataset does report scripts of that kind, so this one genuinely never ran.
Cloudflare's published line describes a Worker a visitor reaches directly, and on this platform no visitor ever reaches one directly. Every asset request goes through our dispatch Worker, because the dispatch Worker owns the route. The assumption was wrong, and it was wrong in the direction that costs us money.
What we measured and what we are still inferring
What was measured is that the dispatch Worker ran sixty times. That those sixty are billed rests on Cloudflare's published statement, not on a number read from an invoice. Nobody has read this account's request usage against a bill.
We are leaving that sentence undecorated, because it is the most trustworthy thing on this page.
Absorbing a flood costs three dollars per ten million requests
Our plan includes twenty million requests in its $25 a month, and then charges $0.30 per extra million. That turns the promise to absorb uncaused traffic into a figure rather than a hope.
| a free static site doing | requests a month | sites inside the pool | cost each beyond it |
|---|---|---|---|
| 5,000 pageviews at four assets each | 20,000 | about 1,000 | $0.01 |
| a 10-million-request bot flood | 10,000,000 | about two | $3.00 |
The bot row is the one to keep in view. We made the promise believing absorption was free; it is $3 per ten million requests, which is still absorbable, and now a number rather than an assumption.
Two honest limits on that arithmetic. The pool is shared across every site on the platform, free and paying alike, so it is a platform-level number rather than a per-customer one. And nothing currently watches it.
Not counting requests is not a promise of unlimited anything
There are bounds here. They sit on the tools rather than on traffic: a certain number of calls a minute for each action your assistant can take, and the current figures are listed in the docs. A bound like that produces a refusal with a sentence in it, not a line on a bill.
That is the difference we were buying. A bound you meet is a sentence you can read, at the moment you meet it, addressed to the person who caused it. A meter you exceed is a number you find later, and it is addressed to you whether or not you had anything to do with it.
The rule, once
Traffic your site did not cause is ours to absorb. Neither plan counts requests, neither counts bandwidth, and what bounds each plan is the small set of things we actually pay for.
Drawn from docs/adr/0012-how-the-platform-charges.md in this project's own record.