DEV Community

Ryan
Ryan

Posted on

Zero Egress: Why I Chose Cloudflare Workers + R2 Over AWS for a File Processing API

Most cloud cost calculators focus on compute and storage. They rarely mention the line item that dominated my bill: egress fees.

I run eazip.io, an API that takes an array of URLs and returns a ZIP archive. The service fetches remote files, streams them into a ZIP64 archive, and stores the result for download. In production, it has processed 550K+ files totaling over 10 TB of archived data.

When I was choosing where to build this, I modeled the costs across AWS, GCP, Azure, and Cloudflare. The results changed my entire architecture.

The Workload

Here's what happens on every API call:

  1. Fetch remote files (1 to 5,000 URLs per job)
  2. Stream them into a ZIP64 archive (up to 50 GB per job)
  3. Store the archive for the customer to download
  4. Serve the download (this is where egress hits)

The critical insight: every byte of the final archive gets transferred twice — once during creation (fetch → process → store) and once during download (store → customer). For a file processing API, egress isn't a rounding error. It's the dominant cost.

Egress Pricing Comparison

Here's what the major providers charge for data transfer out to the internet (as of early 2026, standard pricing tiers):

Provider Egress Cost (per GB) Free Tier
AWS S3 $0.09/GB (first 10 TB) 100 GB/month
GCP Cloud Storage $0.12/GB (first 1 TB) Free tier egress limited
Azure Blob Storage $0.087/GB (first 5 GB free) 5 GB/month
Cloudflare R2 $0.00/GB Unlimited

That's not a typo. R2 charges zero egress. You pay only for storage ($0.015/GB/month) and operations (Class A: $4.50/million, Class B: $0.36/million).

Scenario 1: The Single Large Job

Let's model a realistic scenario: a customer creates a 10 GB ZIP archive and downloads it.

AWS S3:

  • Storage: negligible (temporary)
  • Egress: 10 GB × $0.09 = $0.90
  • If they download it 10 times (sharing with team): $9.00

Cloudflare R2:

  • Storage: negligible
  • Egress: 10 GB × $0.00 = $0.00
  • 10 downloads: still $0.00

One job, one customer, $9 difference. Now multiply that across hundreds of customers.

Scenario 2: Monthly Sustained Usage

A more realistic model: 1,000 jobs per month, average 1 GB per archive, each downloaded twice.

Cost Component AWS S3 Cloudflare R2
Storage (temp, ~100 GB avg) $2.30 $1.50
Egress (2 TB out) $180.00 $0.00
Operations ~$0.50 ~$2.00
Monthly Total $182.80 $3.50

Egress is 98.5% of the AWS bill. The actual compute and storage costs are almost identical between providers. The entire cost difference comes from one line item.

Scenario 3: What Happens at Scale

This is where it gets scary. Let's say the service grows to 10,000 jobs/month (20 TB egress):

Scale AWS Egress R2 Egress
2 TB/month $180 $0
20 TB/month $1,740 $0
200 TB/month $16,200 $0

On AWS, egress grows linearly with success. Every new customer, every additional download directly increases your largest cost. On R2, success doesn't punish you.

For an API business charging $9-29/month, an egress bill of $1,740 makes the unit economics impossible.

"Just Put a CDN in Front of S3"

This is the first objection everyone raises. And for many workloads, it's the right answer. But for a ZIP archive API, it doesn't work.

Every archive is unique. Customer A's ZIP contains different files than Customer B's. The cache hit rate for unique, per-customer archives is effectively zero. CloudFront, Fastly, or any CDN will just pass through to S3, and you still pay S3 egress to the CDN.

CDN caching works when many users request the same content. When every response is unique — which is the case for any file processing, transformation, or generation API — the CDN is just an expensive proxy.

The Hidden Costs You Don't See Coming

Egress isn't the only surprise on an AWS bill for this kind of workload:

NAT Gateway fees: If your processing runs in a VPC (ECS, Lambda in VPC), data passing through a NAT Gateway costs $0.045/GB on top of regular egress. For a service processing terabytes, this doubles your data transfer costs.

Cross-region transfer: If your compute is in us-east-1 but your customer's files are elsewhere, you pay $0.01-0.02/GB for inter-region transfer — before any processing even begins.

Temporary storage I/O: EBS volumes have I/O costs. If you're writing temporary files during ZIP creation, those IOPS add up.

Lambda execution time: A 10 GB ZIP takes minutes to create. At Lambda pricing, long-running file processing jobs are expensive. And Lambda has a 15-minute timeout, so you need step functions or ECS for large jobs.

On Cloudflare:

  • Workers → R2: free (same network)
  • R2 → customer: free (zero egress)
  • No NAT Gateway (Workers run at edge)
  • No cross-region transfer (R2 is globally distributed)

The Architecture That Emerged

The zero-egress model didn't just save money — it shaped the architecture:

Customer Request
      ↓
  [Cloudflare Worker]
      ↓ (fetch remote files)
  [Stream → ZIP64]
      ↓ (multipart upload, free)
  [Cloudflare R2]
      ↓ (download, free)
  Customer
Enter fullscreen mode Exit fullscreen mode

Every data transfer in this pipeline is free. The only costs are:

  • Workers compute: $0.30 per million requests + CPU time
  • R2 storage: $0.015/GB/month
  • R2 operations: pennies per thousand

Total monthly bill for 550K+ files processed and 10 TB+ archived: single-digit dollars.

The same workload on AWS would be estimated at $200-400/month minimum, scaling to $1,000+ as usage grows. And that's before the NAT Gateway surprise.

The Tradeoffs

Cloudflare Workers aren't free of constraints. I want to be honest about what you give up:

128 MB memory limit: You can't buffer large files in memory. I had to build a fully streaming ZIP64 implementation. (I wrote about the technical details in my previous article.)

CPU time limits: Workers get seconds of CPU time, not minutes. For large jobs, I built a checkpoint/resume system that serializes state to R2 and picks up where it left off.

No filesystem: V8 isolates don't have fs. Everything must be streamed or held in memory.

Vendor lock-in: Your code is tied to Cloudflare's runtime. Workers are not standard Node.js — they're a subset of Web APIs. Migrating to AWS Lambda would require significant rewriting.

Smaller ecosystem: Fewer libraries, fewer examples, smaller community compared to AWS Lambda.

For my use case — a data-heavy API where egress dominates costs — these tradeoffs were worth it. For a CRUD app with minimal data transfer, the cost difference wouldn't matter, and AWS/GCP's richer ecosystem might be more valuable.

The Decision Framework

Here's how I'd think about it for your workload:

Choose Cloudflare Workers + R2 when:

  • Data transfer is a significant portion of your workload
  • You serve large files or many downloads
  • Each response is unique (low CDN cache hit rate)
  • You need global low-latency without multi-region setup
  • Cost predictability matters (no surprise egress bills)

Stay with AWS/GCP when:

  • You need specific managed services (RDS, SQS, etc.)
  • Your workload is compute-heavy, not data-heavy
  • Egress is a small fraction of total cost
  • You need the mature ecosystem and tooling
  • Your team already has deep AWS/GCP expertise

Quick Cost Calculator

For a rough estimate of your potential savings, here's a simple formula:

Monthly egress savings = Monthly data out (GB) × $0.09

If you also use NAT Gateway:
Add: Monthly data through NAT (GB) × $0.045
Enter fullscreen mode Exit fullscreen mode

If that number is more than your compute costs, egress is your dominant expense and it's worth evaluating R2.

Results

After 6+ months in production:

  • 550K+ files processed
  • 10 TB+ total data archived
  • Monthly infrastructure cost: single-digit dollars
  • Estimated AWS equivalent: $200-400/month
  • Zero egress bills, ever

The service handles jobs ranging from 1 file to 5,000 files, with archives up to 50 GB. The checkpoint/resume system means large jobs complete reliably despite Worker timeout limits. And the cost stays flat regardless of how many times customers download their archives.

Try It

If you're building something that needs to create ZIP archives from remote URLs, eazip.io wraps this entire architecture into a single API call. Free tier available, no credit card required.

But even if you don't need a ZIP API — if you're building any data-heavy service, model your egress costs before choosing a provider. It might be the most important line item on your bill.


Questions about the cost analysis or the Cloudflare Workers architecture? Drop a comment — happy to share more specific numbers.

Top comments (0)