Cloudflare R2 vs AWS S3 for Developers: Which Should You Choose?

We earn commissions when you shop through the links below.

The debate around Cloudflare R2 vs AWS S3 for developers has been heating up ever since Cloudflare dropped their zero-egress-fee object storage into general availability. As someone who has migrated a production SaaS from S3 to R2 and back again depending on the use case, I have strong opinions on this. Let me break it down properly so you can make an informed decision rather than just chasing hype.

The Core Difference: Egress Fees

The single biggest reason developers are looking at R2 is egress pricing. AWS S3 charges you every time data leaves their network — typically around $0.09 per GB depending on your region. That sounds small until your app serves millions of image downloads or video streams. The bill scales brutally.

Cloudflare R2 charges zero egress fees. None. You pay for storage ($0.015 per GB/month) and operations (Class A writes at $4.50 per million, Class B reads at $0.36 per million), but serving that data to the internet is free.

Here is a rough cost comparison for a typical media-heavy SaaS app serving 10TB of data per month:

  • AWS S3: ~$230 storage + ~$900 egress = ~$1,130/month
  • Cloudflare R2: ~$150 storage + $0 egress = ~$150/month

That is a real difference. But egress cost is not the whole story.

S3 API Compatibility

One of R2’s smartest moves was full S3 API compatibility. If you are already using the AWS SDK to interact with S3, switching to R2 requires almost no code changes. You just point the endpoint at R2 instead.

// AWS S3 client — standard setup
const s3 = new S3Client({
  region: 'us-east-1',
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  },
});

// Cloudflare R2 — same SDK, different endpoint
const r2 = new S3Client({
  region: 'auto',
  endpoint: `https://${process.env.CF_ACCOUNT_ID}.r2.cloudflarestorage.com`,
  credentials: {
    accessKeyId: process.env.R2_ACCESS_KEY_ID,
    secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
  },
});

// Uploading a file — identical for both
const command = new PutObjectCommand({
  Bucket: 'my-bucket',
  Key: 'uploads/image.png',
  Body: fileBuffer,
  ContentType: 'image/png',
});

await r2.send(command);

The migration story is genuinely painless. I have moved apps in under an hour. The SDK compatibility extends to presigned URLs, multipart uploads, and bucket policies — the things you actually use day to day.

Where AWS S3 Still Wins

S3 is not going anywhere, and for several use cases it remains the better choice.

Ecosystem Depth

AWS S3 integrates natively with essentially every AWS service — Lambda triggers, SQS notifications, CloudFront distributions, Athena queries, Glue crawlers, and more. If you are building a data pipeline or event-driven architecture entirely within AWS, that native integration is hard to replicate. R2 has Workers triggers, but the breadth of the AWS ecosystem is unmatched.

Storage Classes and Lifecycle Policies

S3 has sophisticated storage tiers: Standard, Intelligent-Tiering, Glacier, Deep Archive. If you are storing cold data — backups, compliance archives, logs — you can push costs down dramatically with lifecycle policies. R2 currently has one storage class. For hot data that is always being read, R2 wins on egress. For cold archival storage rarely accessed, S3 Glacier can be significantly cheaper overall.

Compliance and Certifications

AWS holds a staggering number of compliance certifications: HIPAA, SOC 2, FedRAMP, ISO 27001, PCI DSS, and many more. If you are in a regulated industry, your legal or security team may mandate AWS simply because it is already on the approved vendor list. R2 is catching up but is not at parity yet.

Regional Availability

S3 lets you pin data to specific regions with precision. R2 uses a simpler hint-based system where you specify a jurisdiction (EU, US, or auto) but Cloudflare decides the exact location. For strict data residency requirements — GDPR, data sovereignty laws — S3 gives you more control.

Where Cloudflare R2 Wins

Public-Facing Asset Delivery

If you serve user-uploaded content — images, documents, videos — directly to browsers, R2 is the obvious choice. The free egress combined with Cloudflare’s built-in CDN (you can connect R2 to a custom domain and it serves through Cloudflare’s edge automatically) means you get global distribution with no extra cost or configuration.

Indie Developers and Bootstrapped SaaS

When you are building a side project or an early-stage SaaS, AWS’s pricing model punishes you for getting traffic. You ship, you get a spike on Hacker News, and suddenly you owe hundreds in egress fees for a free tier product. With R2, that spike costs you almost nothing. The predictability is a genuine stress reliever.

Workers Integration

If you are building on Cloudflare Workers, R2 is a first-class citizen. Binding R2 directly to a Worker means no network hop, no latency from fetching from an external service — you get direct access from your compute to your storage inside Cloudflare’s network.

// Cloudflare Worker with R2 binding
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const key = url.pathname.slice(1);

    if (request.method === 'GET') {
      const object = await env.MY_BUCKET.get(key);

      if (!object) {
        return new Response('Not Found', { status: 404 });
      }

      const headers = new Headers();
      object.writeHttpMetadata(headers);
      headers.set('etag', object.httpEtag);

      return new Response(object.body, { headers });
    }

    return new Response('Method Not Allowed', { status: 405 });
  },
};

Performance: Does It Actually Matter?

Both services deliver solid throughput for most web workloads. S3 has a slight edge in raw write throughput for very large objects and complex multipart operations at scale. R2 benefits from Cloudflare’s edge network for reads, which can reduce latency for globally distributed users without needing a separate CDN layer.

In practice, for the 99% of web apps, you will not notice a performance difference. Pick based on cost and ecosystem fit, not benchmarks.

Practical Decision Framework

Here is how I think about the Cloudflare R2 vs AWS S3 for developers choice in real projects:

Choose R2 if:

  • You serve public assets directly to users (images, videos, downloads)
  • You are building on Cloudflare Workers
  • You are cost-sensitive and expect meaningful read traffic
  • You want dead-simple setup with zero egress anxiety
  • You are an indie dev or small team without enterprise compliance requirements

Choose S3 if:

  • You are deeply embedded in the AWS ecosystem
  • You need cold storage tiers for archival workloads
  • You have strict compliance or data residency requirements
  • You rely on Lambda event triggers from bucket operations
  • You need enterprise support contracts and certifications

Hosting Your App Alongside Your Storage

Storage decisions do not exist in isolation — they connect to where you run your application. If you are deploying on DigitalOcean, their Spaces product offers S3-compatible object storage that is tightly integrated with their compute and networking — worth considering if you already run Droplets or App Platform there. For those wanting truly zero-config deployment alongside their storage, Railway makes it easy to spin up backend services that can connect to either R2 or S3 with environment variables and no infrastructure management overhead.

Migration Tips

If you want to try R2 without committing fully, you can run both in parallel. Use R2 for new uploads going forward and leave existing S3 data in place. Because the API is compatible, your application code can abstract the client behind a single interface and swap providers per bucket or environment. A feature flag or environment variable is enough to switch where new files land.

For bulk migration of existing data, Cloudflare provides a migration tool in the dashboard, or you can use rclone which handles both S3 and R2 natively. I have migrated hundreds of gigabytes in a few hours with rclone sync and no downtime.

Final Verdict

The Cloudflare R2 vs AWS S3 for developers decision comes down to this: if you serve data publicly and pay meaningful egress bills, R2 will likely cut your storage costs significantly while offering comparable developer experience. If you are building deeply within the AWS ecosystem or have enterprise compliance needs, S3 remains the safer and more feature-complete choice.

For new projects, I default to R2 now. The S3 API compatibility means there is almost no switching cost, and the predictable pricing removes a whole category of billing surprises. The only time I reach for S3 first is when I know from day one I am living inside AWS — Lambda pipelines, Athena, Glue, the whole stack. Otherwise, R2 has earned its place as the default object storage choice for most web developers building in 2026.