Cloudflare R2 Pricing 2026: Free Tier Limits, Egress Costs & When to Upgrade
By Nayan Kyada · · 6 min read
Part of The Sanity + Next.js Guide
Cloudflare R2 keeps coming up as an asset storage option for Next.js and Sanity projects, mostly because of one selling point: zero egress fees. But the free tier has real limits, and the per-operation pricing model trips people up. This post breaks down exactly what R2 costs in 2026, where the free tier runs out, and whether it makes sense over S3 or Cloudinary for a content-heavy site.
What the R2 free tier actually includes
R2's free tier resets monthly and covers three distinct cost axes: storage, Class A operations (writes, lists, deletes), and Class B operations (reads/downloads). The headline numbers as of September 2026:
| Resource | Free monthly allowance |
|---|---|
| Storage | 10 GB |
| Class A operations (PUT, POST, DELETE, LIST) | 1,000,000 |
| Class B operations (GET, HEAD) | 10,000,000 |
| Egress (data transfer out) | Unlimited — $0.00 |
Egress being free is the actual differentiator. S3 charges $0.09/GB out to the internet. On a content site serving 20 GB/month of images, that's $1.80 per month from S3 before you touch operations — not catastrophic, but it compounds. Cloudinary's free tier caps at 25 GB of storage and bandwidth combined, so a busy month can knock you into a paid plan without warning.
For a Sanity project where image binaries live in Sanity's CDN and R2 is handling build artifacts, uploaded PDFs, or video segments, the free tier is rarely the bottleneck. Where it gets uncomfortable is when you start routing all your media through R2 — or when you lean on Workers to transform images at the edge.
Paid tier pricing
Once you exceed the free allowances, costs are straightforward but easy to under-estimate if you're only looking at storage:
| Billable item | Price (2026) |
|---|---|
| Storage beyond 10 GB | $0.015 / GB / month |
| Class A operations beyond 1M | $4.50 per million |
| Class B operations beyond 10M | $0.36 per million |
| Egress | $0.00 (always) |
| R2 Super Slurper ingress from S3 | $0.00 |
Storage pricing is competitive — AWS S3 Standard costs $0.023/GB, so R2 is roughly 35% cheaper per gigabyte. But R2's Class A operation cost is higher: S3 PUT requests run $0.005 per thousand ($5 per million) versus R2's $4.50. Close enough that it won't swing a decision.
The number that catches teams out is Class A operations during CMS-driven publishing workflows. Every time a Sanity webhook fires and your Next.js route handler writes a revalidated JSON blob or a pre-generated OG image back to R2, that's a Class A op. On a busy editorial day with 500 publishes, each triggering a cache-busted PUT, you're at 500 operations — nothing near the limit. But if you're also listing bucket contents for a sitemap job or running bulk migrations, the counter rises faster.
R2 vs S3 vs Cloudinary: cost comparison for a content site
Assumptions: 50 GB stored, 100 GB egress per month, 5 million Class A ops, 50 million Class B ops — roughly a mid-size marketing site with a lot of image variants.
| Provider | Storage | Egress | Operations | Monthly total (approx.) |
|---|---|---|---|---|
| Cloudflare R2 | $0.60 | $0.00 | $22.50 A + $14.40 B | ~$37.50 |
| AWS S3 Standard | $1.15 | $9.00 | $25.00 A + $20.00 B | ~$55.15 |
| Cloudinary (Growth) | $149/month flat (includes transforms) | included | included | ~$149 |
Cloudinary is only worth the premium if you need on-the-fly image transformations — resizing, format conversion, face-detect cropping — without writing any code. If you're already handling image optimisation through next/image and serving pre-processed assets, you're paying for features you don't use.
R2 wins on egress-heavy workloads. S3 wins if you're already deep in the AWS ecosystem and want Lambda@Edge, SQS triggers, or tight IAM integration.
What triggers an R2 upgrade on a real Next.js project
Three scenarios push a project out of the free tier faster than expected:
1. Storing pre-generated Open Graph images. If you're generating OG images at build time or on-demand via a route handler and caching them in R2, every unique URL is a PUT. A blog with 2,000 posts means 2,000 Class A ops minimum — well inside the free tier. But if you're also generating per-locale variants, per-date variants, or resized versions, you can hit 10,000+ ops in one deployment.
2. ISR revalidation artifacts. Some teams write JSON snapshot files to R2 as part of their ISR warm-up strategy. Each Sanity webhook → revalidate → write-back cycle = 1 Class A op. At scale this adds up, but you'd need hundreds of publishes per day before it registers.
3. Video uploads routed through Workers. If you're uploading Mux-bound video files through a Cloudflare Worker that stages to R2 first, large multipart uploads count each part as a separate Class A op. A 2 GB video split into 5 MB parts is ~400 ops per upload.
For most Next.js + Sanity setups, R2 stays inside the free tier for months. The upgrade trigger is almost always storage (exceeding 10 GB) rather than operations.
R2 pricing requires a Workers Paid plan
This is the detail that surprises people: R2 requires a Cloudflare account on the Workers Paid plan ($5/month) to use in production. The free tier of R2 is accessible, but you cannot bind R2 buckets to deployed Workers or Pages Functions without the paid Workers plan.
If you're running a Next.js site on Cloudflare Pages and want R2 access via a route handler, you need to budget that $5/month base cost. It's not listed prominently in the R2 pricing page — it's buried in the Workers limits table.
For context: Vercel's equivalent (Vercel Blob, backed by Cloudflare R2 under the hood) starts at $0.023/GB on the Pro plan, with no separate operations charge visible to the user. You pay more per gigabyte but don't think about Class A/B splits. If you're already on Vercel Pro ($20/month), Vercel Blob's simplicity might be worth the storage markup.
When R2 makes sense vs when it doesn't
R2 is worth it when: you're already on Cloudflare for DNS/CDN, your primary cost driver is egress, you want a zero-surprise bill for serving static assets globally, and you're comfortable wiring up S3-compatible SDKs in your Next.js route handlers.
Skip R2 when: you need image transformation logic (use Sanity's native CDN or Cloudinary), you're on Vercel and want zero infra config (use Vercel Blob), or your team isn't familiar with Cloudflare Workers bindings and doesn't want to learn them for a side project.
The free tier is genuinely useful for small to mid-size projects. The $5/month Workers Paid base cost is the real minimum — plan for it from day one.