
Cloudflare R2 vs Amazon S3: Egress Can Overwhelm Storage Price

Cloudflare R2 can cost substantially less than Amazon S3 when stored files are downloaded directly by internet users: the transfer bill can be much larger than the storage bill. Cloudflare’s R2 pricing schedule lists Standard storage at $0.015 per GB-month, Class A operations at $4.50 per million, Class B operations at $0.36 per million and internet egress at no charge. Free egress does not make reads free once they exceed the included operation allowance.
S3 can make more sense when an application reads objects within the bucket’s AWS Region or depends on services already built around S3. Its cost changes with storage class, request volume, retrievals and the route data takes. The comparison therefore turns on the full workload, especially whether users download from the object store directly or through a CDN.
Set the boundaries of the calculation
The three hypothetical monthly workloads below count billed GB-months, PUTs, GETs, retrieved bytes where applicable and transfer to the internet. They assume one stored copy, no replication, no encryption-key charges and no paid application compute. A stated quantity of 1,000 GB-months means 1,000 billable gigabytes held for the month; it is not a conversion from a loosely labeled terabyte.
For S3 Standard, an AWS cost table gives US East (N. Virginia) rates of $0.023 per GB-month, $0.005 per 1,000 PUTs and $0.0004 per 1,000 GETs. Those are the storage and request inputs for the first two examples. The calculations assume no promotional credits or account-specific discounts.
An AWS direct-delivery example uses a $0.09-per-GB internet-transfer rate after the first 100 GB each month, an allowance aggregated across eligible AWS services. The direct-download model assumes that allowance is still available. Traffic elsewhere in the account, another region or a different transfer tier would change its transfer line.
Direct downloads: outbound bytes dominate
Suppose a service stores 1,000 GB for a month, makes 100,000 PUTs and one million GETs, and sends 10,000 GB directly to internet users without a CDN. R2 Standard charges $14.85 for storage: 1,000 GB-months less its 10 GB-month monthly allowance, multiplied by $0.015. Both request counts fit within its included monthly allowances of one million Class A and ten million Class B operations, leaving a modeled R2 object-storage total of $14.85.
On S3 Standard, storage is $23, PUTs are $0.50 and GETs are $0.40. After the assumed 100 GB internet-transfer allowance, 9,900 GB at $0.09 adds $891. The modeled S3 total is $914.90. The $891 transfer line overwhelms the $23 storage line; it is the reason these otherwise similar storage quantities produce such different totals.
This example applies to direct S3 downloads. A cache changes both the number of requests reaching the bucket and which service sends bytes to viewers. Charging the same 10,000 GB as direct S3 internet transfer after placing CloudFront in front of the bucket would misstate that architecture.
Cached delivery: the origin bill is only part of the bill
Keep the same 1,000 GB stored, 100,000 PUTs and 10,000 GB delivered to viewers, but place a CDN in front of the objects. Assume 100 million viewer requests and a 95% cache hit rate by both request count and bytes. That leaves five million origin GETs and 500 GB fetched from storage. Equal request and byte hit rates are an explicit simplifying assumption: a cache could serve many small requests while still fetching a large share of bytes from its origin.
Under those assumptions, R2 Standard remains at $14.85 for storage, with five million origin reads inside its Class B allowance. S3 Standard’s origin subtotal is $25.50: $23 for storage, $0.50 for PUTs and $2 for five million GETs. Amazon S3’s transfer rules exempt transfers from S3 to CloudFront, so the 500 GB fetched by that CDN does not incur the direct-to-internet S3 charge used in the previous model.
Neither origin subtotal is a complete delivered-content price. CloudFront can charge for viewer transfer and requests; a Cloudflare delivery path can involve other metered services. The 100 million viewer requests must be priced on the delivery layer, while the five million misses drive the modeled object-store GET count. Comparing only the origin subtotals would hide the cost of serving viewers.
A public account from an SEC-filing archive operator reported roughly 28 TB distributed over 174 million requests and calculated $10.80 for about 29.9 million R2 Class B operations. The operator said the archive used caching and acknowledged that a simple direct-S3 transfer comparison was naive. The $10.80 figure describes the reported Class B calculation, not the full cost of that delivery system.
Infrequent access: retrieval belongs in the archive model
Consider a separate hypothetical month with 10,000 GB held throughout the month, 1,000 GETs retrieving 100 GB in total and no new writes. Assume objects are large enough to avoid S3 Standard-Infrequent Access’s minimum billable object-size adjustment and remain stored long enough to avoid minimum-duration adjustments. On the S3 path, an application reads the objects in the bucket’s AWS Region, so there is no internet-transfer line.
R2 Infrequent Access costs $0.01 per GB-month for storage, $0.90 per million Class B operations and $0.01 per GB retrieved. Its Standard-class free allowance does not apply, and Cloudflare rounds operations up to the next billing unit. This workload therefore costs $100 for storage, $0.90 for the 1,000 reads and $1 for retrieval: $101.90 before application costs.
Using US East rates of $0.0125 per GB-month for S3 Standard-Infrequent Access storage, $0.01 per GB retrieved and $0.001 per 1,000 GETs, the corresponding S3 calculation is $125 + $1 + $0.001, or about $126. Both models charge for retrieved bytes even though the reads stay off the public internet. S3 also has archive classes with different prices and restore behavior, so their lower storage rates cannot be substituted into this immediately accessible comparison.
Where AWS integration changes the decision
If the consuming application already runs in the bucket’s AWS Region, S3’s same-Region transfer exemption removes the direct-internet charge that drove the first example. Keeping objects in S3 can also avoid changes to existing permissions, lifecycle rules, replication and services that depend on those objects. The value of that continuity is operational rather than a per-GB discount, and it varies with the system being maintained.
The strongest case for R2 is a workload that sends substantial volumes directly to public users while keeping request charges manageable. For CDN delivery, the relevant comparison is the complete viewer and origin bill, with cache hit rates measured separately for requests and bytes. For infrequently read data inside AWS, retrieval costs, storage class rules and the value of the existing AWS path may carry more weight than internet egress.
Also read:
Related articles


Sentry vs Datadog: Error Debugging or Full-Stack Context Decides It

CrowdStrike Enters OpenAI Marketplace—but Only Eligible Spend Transfers

Salesforce Agrees to Buy Listen Labs—AI Interviews Move Into CRM

Yext Agrees to Buy Flamel.ai—Paid Media Joins Local Search Data

Ascerta Raises $18M—AI Spend Still Needs a Business-Value Test
Subscribe to our newsletter
Get the latest Web3, AI, and crypto news delivered straight to your inbox.