The bill for object storage is rarely about storage.
Look at a large S3 invoice and the gigabytes you keep are often the smaller half. The larger half is the gigabytes you send — and that line item does something no other line item does: it makes leaving expensive. A dataset you can’t afford to move isn’t just stored somewhere. It’s held there.
Cloudflare R2 attacks that specific line by charging nothing for it. That’s the headline, it’s true, and it’s not the whole story. Here is what each side actually bills, with the numbers from both vendors’ own documentation, checked in August 2026.
Why Egress Exists at All
Storing bytes is cheap and getting cheaper. Moving bytes across a provider’s network edge is where the cost curve stops falling and where the pricing power sits.
The asymmetry is the tell. On S3, data in from the internet is free. Data out is not. So is data between buckets in the same region, data from S3 to any AWS service in the same region, and data out to CloudFront. Getting your data in costs nothing; getting it out to anywhere that isn’t AWS costs per gigabyte.
That’s not a conspiracy — bandwidth genuinely costs money — but the shape of it means the meter runs hardest precisely when you use your data somewhere else.
The Headline Numbers
S3 gives you the first 100 GB per month of data transfer out to the internet free, aggregated across all AWS services and regions (excluding China and GovCloud). After that, you pay per gigabyte at a rate that varies by region and volume. AWS’s own documentation, in a Multi-Region Access Point example, quotes $0.09 per GB for transfer out from Europe (Ireland) to the internet.
Cross-region transfer is cheaper but still metered: AWS quotes $0.01/GB from N. Virginia to Ohio and $0.02/GB from Oregon to N. Virginia.
R2 charges $0 for egress on every storage class. Cloudflare’s footnote defines the boundary precisely: egressing directly from R2 — through the Workers API, the S3-compatible API, or r2.dev domains — incurs no data transfer charge. If you attach other metered services to the bucket, those services may bill you.
At 5 TB of monthly egress from Ireland — comfortably inside the first pricing tier — that is roughly $450 on one line, before anyone has stored anything.
Resist the urge to scale that up by multiplication. AWS applies volume tiers, and states that rate tiers take into account your aggregate data transfer out across all AWS services. The per-gigabyte figure everyone quotes is the first tier; later gigabytes cost less. A flat multiplication across 50 TB overstates the bill — the direction is right, the total is not.
What R2 Bills Instead
R2 is not free. It moves the meter from bytes-out to operations, and for some workloads that meter runs fast.
Standard storage:
| Standard | Infrequent Access | |
|---|---|---|
| Storage | $0.015 / GB-month | $0.01 / GB-month |
| Class A operations | $4.50 / million | $9.00 / million |
| Class B operations | $0.36 / million | $0.90 / million |
| Data retrieval | None | $0.01 / GB |
| Egress | Free | Free |
The free tier covers 10 GB-month of storage, 1 million Class A and 10 million Class B operations per month — Standard only, not Infrequent Access.
The split matters more than the rates:
- Class A (expensive, mutating):
PutObject,CopyObject,ListObjects,ListBuckets,PutBucket, the whole multipart family, lifecycle transitions, andPutBucket*configuration calls. - Class B (cheap, reading):
GetObject,HeadObject,HeadBucket,UsageSummary,GetBucket*calls. - Free:
DeleteObject,DeleteBucket,AbortMultipartUpload.
Note that listing is Class A. A job that lists a bucket on every iteration is paying the expensive rate for what feels like a read.
Cloudflare’s own asset-hosting example makes the point better than any argument. Host 100,000 files averaging 100 KB, serve 10 million reads per day:
| Usage | Billed | |
|---|---|---|
| Storage | 100,000 × 100 KB | $0.00 (under free tier) |
| Class A | 100,000 writes | $0.00 (under free tier) |
| Class B | 300 million reads | $104.40 |
| Total | $104.40 |
Storage: nothing. Egress: nothing. The entire bill is read operations. If you migrate to R2 expecting a bill dominated by gigabytes, you will be surprised by a bill dominated by requests.
The Fine Print That Moves the Total
Headline rates are the easy part. These are the clauses that change what you actually pay, and they cut both ways.
S3 measures in binary gigabytes. AWS states plainly that S3 storage usage is calculated in binary GB, where 1 GB is 2³⁰ bytes — a gibibyte. If you sized your budget with decimal gigabytes, you are off by about 7.4% before anything else happens.
Egress is tiered, and the tiers are account-wide. The headline per-gigabyte rate applies to the first tier only. AWS notes that rate tiers take into account your aggregate usage for data transfer out across all AWS services — so your S3 bill depends on what CloudFront, EC2 and everything else sent out that month. This cuts both ways: it makes single-rate estimates too high, and it makes per-service attribution harder than it looks.
LIST is billed at the PUT rate on S3. Not the GET rate. AWS says so directly: “LIST requests for any storage class are charged at the same rate as S3 Standard PUT, COPY, and POST requests.” Paginating through a large bucket is not a cheap read operation.
A dropped connection can cost more than you received. This one is worth reading twice. AWS documents that if you request a 10 GB object and terminate after receiving 2 GB, S3 attempts to stop streaming but does not do so instantly — you may be billed for 3 GB. Clients that abort downloads aggressively pay for bytes nobody consumed.
R2 rounds up to the next billing unit. Cloudflare’s examples: one million and one operations bills as two million operations; 1.1 GB-month bills as 2 GB-month. On small accounts this rounding is proportionally brutal.
Minimums bite on both sides. S3 Standard-IA and One Zone-IA have a minimum billable object size of 128 KB and a 30-day minimum duration; Glacier tiers run 90 or 180 days and add 40 KB of metadata per archived object. R2’s Infrequent Access carries a 30-day minimum duration.
Unauthorized requests are free on R2. Cloudflare states you are not charged for operations where the caller lacks permission (HTTP 401). Worth knowing if your bucket is publicly addressable and attracting noise.
When Infrequent Access Costs More Than Standard
The clearest trap in R2’s pricing is its own cheaper tier. Cloudflare publishes both examples side by side.
Write 1,000 objects of 1 GB, read each 1,000 times over the month:
- Standard: $14.85 total (990 billable GB-months after free tier; operations covered by free tier)
- Infrequent Access: $29.90 total
IA is twice the price. The mechanics: IA has no free tier, its Class A operations cost double, its Class B cost 2.5×, retrieval adds $0.01/GB, and the 30-day minimum means storing objects for five days still bills 1,000 GB-months rather than 167.
The rule that falls out: Infrequent Access is a bet that you will not read the data. Break that bet and you pay more than you would have on Standard.
What the EU Data Act Changed
Regulation (EU) 2023/2854 — the Data Act — entered into force on 11 January 2024 and has applied since 12 September 2025. Among its measures are rules letting customers switch effectively between providers of data-processing services, aimed explicitly at unlocking the EU cloud market.
The interesting part is how that shows up in a price list. AWS’s S3 pricing page now carries this line:
EU customers may request reduced data transfer rates for eligible use cases under the European Data Act. Please contact AWS Customer Support for more information.
Read it carefully. The relief exists, and it is a request you have to make, for eligible use cases, through support. It is not a rate change applied to your account because you are in the EU.
That is the practical shape of the regulation today: the lock-in mechanism is now negotiable rather than absent. If you are planning a migration out of AWS from the EU, opening that support case is a concrete, dated step in your plan — not a footnote.
So Which One
The decision is not “which is cheaper.” It is which meter matches your traffic.
R2 wins decisively when bytes leave the cloud. Public asset delivery, media, downloads, backups pulled by systems outside AWS, anything served to the open internet at volume. This is the case R2 was built for and the numbers aren’t close.
S3 stays sensible when bytes never leave. If your consumers are EC2, Lambda, Athena or Glue in the same region, you are already paying zero egress. Migrating that workload to R2 to save on a line you aren’t being charged for is motion without progress.
Count operations before you commit. A workload with many small objects and high request rates can cost more on R2 than the egress it saves. Cloudflare’s own $104.40 example is entirely operations.
Check what you lose. R2 speaks the S3 API, but “S3-compatible” is not “S3-identical.” Before migrating, verify the specific features your stack depends on rather than assuming parity.
Migration tooling is free, mostly. Cloudflare’s Super Slurper (bulk copy) and Sippy (incremental, migrate-on-read) cost nothing to use — you pay only the Class A operations they generate against your R2 bucket. Your source bucket may still bill you for the reads and the egress on the way out, which is the last irony of the whole arrangement: leaving costs egress.
A Checklist Before You Move
- Pull last month’s actual egress in GB from Cost Explorer — not an estimate.
- Count your requests, split into writes/lists (Class A) and reads (Class B). Multiply by R2’s rates.
- Check how much of your traffic is same-region AWS-to-AWS. That part is already free and gains nothing.
- Re-measure storage in binary vs decimal gigabytes so you compare like with like.
- If any bucket uses IA or Glacier, check minimum-duration and minimum-object-size penalties before transitioning anything.
- If you are in the EU, open the AWS support case about Data Act transfer rates — get the number in writing before you model the migration.
- Budget the one-time cost of the migration itself: reads plus egress on the source side.
The Real Point
Egress pricing is not really a bandwidth charge. It is the mechanism that converts stored data into retained customers, which is why a competitor attacking exactly that line was always going to get attention — and why a regulator eventually did too.
But “free egress” is a claim about one line on an invoice, not about the invoice. Cloudflare bills you for operations, rounds usage up, and penalises the wrong storage class just as firmly as AWS does. The provider changed; the need to read the fine print did not.
Price your own workload against both meters. The answer is different for a media CDN and for an analytics pipeline that never leaves us-east-1, and anyone who tells you otherwise is quoting a headline rate.
Related reading: on keeping data movable in the first place, see backups are not disaster recovery and sovereign by design. For the analytics side of storage economics, see BigQuery vs Snowflake.
Sources: all figures come from vendor documentation checked in August 2026 — Cloudflare R2 pricing (updated 7 August 2026), Amazon S3 pricing, and the European Commission’s Data Act page. Rates change; verify against the vendor calculators before committing a budget.





From the community
Discussion on the Fediverse
Replies from Mastodon and Bluesky — straight from the open web, no tracking.
Loading replies …
No replies yet. Start the conversation:
Replies could not be loaded right now.