Cloudflare R2 doesn’t charge you for data leaving its storage, which is a massive departure from how cloud object storage typically works.
Let’s see it in action. Imagine you’re serving images for a website. Normally, you’d store them in something like AWS S3, and Cloudflare would cache them. When a user requests an image not in Cloudflare’s cache, Cloudflare pulls it from S3, incurring egress fees from AWS, which then get passed on to you. With R2, Cloudflare pulls the image from R2, and because it’s Cloudflare to Cloudflare, there’s no egress charge.
{
"name": "my-website-assets",
"accounts": [
{
"id": "02f32e34-74c3-49b0-9b1e-1234567890ab",
"name": "My Company",
"storage_provider": "cloudflare-r2",
"buckets": [
{
"name": "website-images",
"region": "us-east-1",
"public_access": true,
"cors_configuration": {
"cors_rules": [
{
"allowed_origins": ["https://www.example.com"],
"allowed_methods": ["GET"],
"max_age_seconds": 3600
}
]
}
}
]
}
]
}
This JSON represents a hypothetical configuration. website-images is an R2 bucket. Notice public_access is true – this is common for web assets, making them directly accessible via a URL. The cors_configuration is crucial for web applications; it tells the browser that https://www.example.com is allowed to make requests to this bucket, preventing cross-origin errors when your JavaScript tries to load an image.
The problem R2 solves is the exorbitant cost of data egress from traditional cloud storage providers. For applications with high read/write volumes or serving large amounts of data to end-users, egress fees can quickly become the dominant cost factor, often dwarfing storage costs themselves. R2’s zero egress fee model directly attacks this pain point, making it economically viable to host and serve large datasets without fear of unpredictable, runaway charges.
Internally, R2 leverages Cloudflare’s global network. When you upload a file, it’s distributed across Cloudflare’s data centers. When a request comes in, Cloudflare serves it from the nearest edge location. If the data isn’t already at that edge location, Cloudflare fetches it from the R2 "origin" – which is also part of Cloudflare’s infrastructure. The magic is that this internal data movement between R2 storage and the Cloudflare edge doesn’t incur egress charges because it never leaves Cloudflare’s network. You only pay for the storage itself (which is competitively priced) and a small fee for operations (like PUTs and GETs), but not for the amount of data transferred out.
The exact levers you control are primarily around bucket creation, access policies (like IAM for programmatic access or public/private settings), CORS, and lifecycle management. You can set up policies to automatically delete old files, for example, to manage storage costs. The integration with Cloudflare Workers is also a powerful lever; you can write serverless functions that run at the edge to dynamically process, transform, or authenticate access to R2 objects before they are served.
Many people assume R2 is just a "drop-in replacement" for S3. While it offers an S3-compatible API, the underlying architecture and pricing model are fundamentally different. You can’t just point an existing S3 application at R2 and expect everything to work identically, especially regarding fine-grained access control or specific AWS-only features. The real benefit comes from understanding how R2 fits into the broader Cloudflare ecosystem, where its zero-egress nature unlocks new cost efficiencies when combined with Cloudflare’s CDN and Workers.
The next challenge you’ll likely face is managing data synchronization and redundancy with other cloud providers or on-premises storage.