Cloudflare R2 vs S3 + CloudFront: Honest Cost Comparison

Cloudflare R2 has no egress fees. Workers charge per request. Here's an honest cost comparison against the AWS edge stack — and when Cloudflare actually wins.

By Andrii Votiakov on 2026-01-20

Cloudflare's pitch is simple: no egress fees on R2, Workers at the edge instead of Lambda@Edge or CloudFront Functions, and a flat pricing model that doesn't penalise you for moving data around. It sounds compelling. But "no egress" is only part of the story, and I've seen teams switch to Cloudflare expecting big savings and find the bill was roughly the same — or higher — because they modelled it wrong.

Here's the actual comparison, with real numbers.

Quick answer

Cloudflare R2 + Workers beats S3 + CloudFront + Lambda for workloads with high egress volume (>5 TB/month), frequent small object reads, or global edge compute with low cold-start requirements. S3 + CloudFront wins on deep AWS integration, complex IAM / access control, large sequential reads, and workloads under ~1 TB/month egress where CloudFront's free tier absorbs most costs. The crossover point is usually around $400-600/month in AWS egress costs.

How the pricing models differ

S3 + CloudFront + Lambda@Edge (AWS)

Component Pricing
S3 storage $0.023/GB/month (Standard)
S3 GET requests $0.0004 per 1,000
CloudFront egress $0.0085-0.085/GB (tiered, region-dependent)
CloudFront HTTPS requests $0.0100 per 10,000
Lambda@Edge $0.60/million requests + $0.00005001/GB-second
Data transfer S3 → CloudFront Free (same-region)

CloudFront gives you 1 TB free egress per month on the free tier. That absorbs a lot of small workloads. Above 1 TB, you start paying $0.085/GB in the US, dropping to $0.0085/GB at >5 PB/month.

Cloudflare R2 + Workers

Component Pricing
R2 storage $0.015/GB/month
R2 Class A operations (writes, lists) $4.50 per million
R2 Class B operations (reads) $0.36 per million
R2 egress to internet $0
Workers free tier 100,000 requests/day
Workers Paid $5/month + $0.50 per million requests over 10M
Workers CPU $0.02 per million CPU-milliseconds over 30M

The absence of egress fees on R2 is real. Data leaving R2 to the internet costs nothing — not the reduced rate AWS charges at scale, genuinely zero.

Scenario 1: Image CDN, 5 TB/month served

A typical setup: user-uploaded images stored in S3/R2, served globally via CDN/edge, with light image transformation at the edge.

AWS (S3 + CloudFront):

  • Storage: 500 GB × $0.023 = $11.50
  • CloudFront egress: 5 TB × $0.085/GB (US rate) = $425
  • CloudFront requests: 50M × $0.010/10k = $50
  • Lambda@Edge (resize): 50M × $0.60/M + compute = $30 + $25 = $55

Total: ~$541/month

Cloudflare (R2 + Workers):

  • Storage: 500 GB × $0.015 = $7.50
  • R2 reads: 50M × $0.36/M = $18
  • Workers (transforms): $5/month base + 50M at $0.50/M over 10M = $5 + $20 = $25
  • Egress: $0

Total: ~$50.50/month

At this scale, Cloudflare is roughly 10x cheaper. The difference is almost entirely egress.

Scenario 2: Small workload, 200 GB/month served

AWS (S3 + CloudFront):

  • Storage: 50 GB × $0.023 = $1.15
  • CloudFront egress: 200 GB — within free tier (1 TB/month) = $0
  • Requests: 2M × $0.010/10k = $2

Total: ~$3.15/month (CloudFront free tier covers the egress entirely)

Cloudflare (R2 + Workers):

  • Storage: 50 GB × $0.015 = $0.75
  • R2 reads: 2M × $0.36/M = $0.72
  • Workers: within free tier = $0

Total: ~$1.47/month

Cloudflare is still cheaper, but the difference is cents. At this scale, the deciding factor is where the rest of your infrastructure lives — staying on AWS is almost certainly the right call.

Scenario 3: Global API at the edge, 10M requests/month

This is a common Workers use case: a lightweight API (auth checks, A/B routing, personalisation) running at the edge rather than in a central Lambda or EC2 fleet.

AWS (CloudFront Functions + Lambda@Edge):

  • CloudFront Functions: 10M × $0.10/M = $1
  • Lambda@Edge (if needed for heavier logic): 10M × $0.60/M + compute ~$6-15

Total: $7-16/month

Cloudflare Workers:

  • 10M requests, Workers Paid: $5/month flat + 0 overage (within 10M included)

Total: $5/month

Workers wins on price here, and also on DX (developer experience). Workers cold starts are sub-millisecond; Lambda@Edge cold starts are 50-200ms. For latency-sensitive edge compute, that difference matters more than the price.

When Cloudflare wins

  • High egress volume (>5 TB/month): egress fees on AWS dominate; R2's zero-egress model saves real money
  • Global media delivery: images, video previews, documents served to a global audience
  • Edge compute at high request rates: Workers is genuinely cheaper than Lambda@Edge at >10M requests/month
  • Static site hosting at scale: Pages + R2 is a simple, cheap combination
  • Multi-cloud or AWS-exit scenarios: R2's S3-compatible API makes migration manageable

When AWS wins

  • Deep AWS service integration: If your R2 data needs to talk to RDS, SQS, SNS, or EventBridge, staying in S3 avoids a cross-cloud hop
  • Complex IAM and access patterns: S3 bucket policies, presigned URLs, and IAM are more mature than R2's equivalent
  • Large sequential reads (analytics, ML training): S3's Select and the overall S3-to-analytics pipeline (Athena, Glue, SageMaker) has no Cloudflare equivalent
  • Compliance and certifications: AWS has more certifications relevant to regulated industries
  • Under 1 TB/month egress: CloudFront's free tier makes the cost difference negligible

The migration path

If you're moving from S3 + CloudFront to R2, the migration is less painful than it sounds. R2 exposes an S3-compatible API — most SDKs work by changing the endpoint and credentials. The main work is:

  1. Copy objects to R2 using rclone or the R2 migration tool
  2. Update your application endpoint configuration
  3. Set up a Workers route or a custom domain pointing to R2
  4. Validate behaviour (redirect handling, CORS, presigned URL equivalents)

Presigned URLs work differently in R2 — they're supported but have a 7-day maximum expiry vs S3's 7 days as well (same limit, different implementation details to test).

Realistic numbers

A client running a media-heavy SaaS (~8 TB/month served, 60M requests/month):

Component AWS monthly cost Cloudflare monthly cost
Storage (1.2 TB) $27.60 $18
Egress/CDN $680 $0
Requests + compute $90 $35
Total $797/month $53/month

Migration took 4 days. Ongoing saving: ~$744/month, ~$8,900/year.

The workload was a good fit: high egress, no AWS service dependencies, no complex IAM requirements. Not all migrations look this clean.


If you're trying to work out whether your current CDN and edge stack is overkill or under-optimised, I'm happy to run the numbers with you. Book a call.