Cloudflare R2 vs S3 vs Supabase Storage in 2026: which to pick
Cloudflare R2 charges no egress, S3 has the deepest ecosystem, Supabase Storage hides the wiring. Here is how to pick for a 2026 SaaS without overpaying.
Object storage is a flat namespace of unstructured blobs accessed over HTTP, billed by stored bytes and by traffic. Three options dominate the practical SaaS conversation in 2026: Cloudflare R2 (zero egress fees), Amazon S3 (the original, deepest ecosystem), and Supabase Storage (PostgREST-fronted, integrated with row-level security). All three speak the S3 API, all three replicate across data centres, all three charge by the GB. The difference shows up the moment you start moving bytes out.
TL;DR. Pick R2 when egress dominates the bill, S3 when you live inside AWS or need a feature only AWS ships, Supabase Storage when the data is small, tied to auth, and you do not want to wire a second service. Avoid Supabase Storage as a general-purpose object store. Avoid R2 if you depend on Glacier or AWS-region-specific compliance certificates. Avoid S3 if your traffic is mostly public assets.
Pricing snapshot
AxisCloudflare R2Amazon S3 StandardSupabase StorageStorage / GB / month$0.015$0.023$0.021 (after free tier)Egress to internet$0~$0.09 / GB~$0.09 / GB (after included)Class A ops (writes)$4.50 / million$5.00 / millionCounted as DB requestsClass B ops (reads)$0.36 / million$0.40 / millionCounted as DB requestsFree monthly allowance10 GB stored, 10M reads, 1M writesNone on paid accounts1 GB on Free, 100 GB on ProS3 API compatibilityMost of v4, some gapsNativeYes, via Storage v3 APINumbers are list-price US-East-equivalent, before volume discounts. AWS reserved capacity, S3 Intelligent-Tiering, and enterprise Supabase plans all change the equation. Benchmark against your own traffic shape before signing.
Where Cloudflare R2 wins
The headline is egress. S3 charges roughly $0.09 per GB to send data to the public internet. R2 charges nothing. For a video platform serving 100 TB of footage to viewers each month, that is the difference between a $9,000 bill and a $1,500 bill, and the gap widens linearly with traffic. Cloudflare's own announcement framed R2 as a direct attack on this part of the AWS model. Two years on, the pricing has held.
R2 also bills storage at $0.015/GB/month, 35% cheaper than S3 Standard. For a million-image marketplace where each user requests the same product photo through a CDN once and never again, the egress savings are limited but storage compounds month after month, and you still come out ahead.
R2 speaks most of the S3 v4 API, so existing AWS SDK code mostly works with a custom endpoint and a new key pair. The gaps are real but manageable for most workloads: no Glacier-equivalent tiers, no per-object ACLs (use bucket policy and signed URLs instead), no multi-region buckets in the AWS sense (R2 is automatically distributed across Cloudflare's network).
Where Amazon S3 wins
S3 is 20 years old and has the deepest ecosystem of any object store. If your processing pipeline reads from S3 via Athena, Glue, EMR, or Lambda triggers, leaving the AWS region costs more than the storage difference will ever save. Same for compliance: AWS has HIPAA, FedRAMP, IRAP, and dozens of region-specific certifications that R2 does not match line for line. A bank in Frankfurt that needs eu-central-1 with a specific BSI attestation has one realistic option.
S3 also ships features R2 does not. S3 Intelligent-Tiering auto-moves rarely accessed objects to cheaper storage classes (down to roughly $0.004/GB/month for Deep Archive), with a small monitoring fee. For a 50 TB archive of cold logs you read twice a year, Intelligent-Tiering plus Deep Archive beats R2's flat $0.015 by a wide margin, even after egress. Object Lambda, S3 Object Replication across accounts, and S3 Batch Operations have no R2 equivalent in 2026.
The catch is the egress bill, and it does not show up in development. It shows up when a product video gets shared on social and you pay for every download. Build with S3, but model your monthly egress before committing.
Where Supabase Storage wins
Supabase Storage sits behind PostgREST and shares the same row-level security policies as your tables. An access_policy on the storage object inherits from the row that references it, so a logged-in user can fetch only the files their tenant owns without a second authorisation layer. The API surface is the same Supabase JS client you use for queries, which means no extra SDK, no second key rotation flow, and no separate IAM model.
That integration is the whole point. For an internal tool that stores a few hundred PDFs per tenant or a SaaS where users upload avatars and CSV imports, Supabase Storage removes a service from the stack. The Pro plan ($25/month) includes 100 GB of storage and 200 GB of egress, which covers the long tail of small SaaS apps before they need to think about object storage as a line item.
It loses badly past that envelope. If you store more than a few hundred GB or push more than a few TB of egress per month, Supabase's per-GB pricing aligns with S3, and you give up R2's egress savings and S3's tiering options for the convenience. The right move at that scale is to migrate hot media to R2 while keeping user-private documents on Supabase Storage. We have done this for two SaaS clients in the last year.
Compatibility, migration, and the S3 API gotcha
All three providers expose an S3-shaped API, but the edges differ. R2's API skips signed POST policies (use signed URLs instead), and presigned URL TTLs cap at 7 days where S3 allows configurable limits. Supabase Storage's S3 v3 endpoint is opt-in per project and gates some operations behind the Supabase JS client. The AWS SDK for JavaScript works against R2 and Supabase with a custom endpoint, but boto3 in Python has quietly tripped on R2's Conditional PUT semantics for years. Check the bug tracker before you assume parity.
Migrations between the three are mostly bandwidth-bound, not API-bound. rclone with S3-compatible backends handles all three, and Cloudflare's Super Slurper service exists specifically to pull S3 buckets into R2 without paying double egress. The hidden migration tax is anything written against AWS-specific features: lifecycle rules, S3 Select, Object Lambda, replication topology. Rewrite that code before you start copying objects, not during.
What we ship by default in 2026
For a new Next.js SaaS where the database is Supabase and we expect a mix of small user uploads (avatars, attachments) and large public media (videos, images served via CDN), the default stack is two buckets. Supabase Storage for anything tied to a logged-in user where the RLS join matters: profile photos, document uploads, tenant-scoped CSVs. R2 behind a custom Cloudflare CDN for everything served broadly: marketing images, public product photos, video assets, downloadable resources.
S3 enters the picture in two cases. Existing customers already on AWS who need a same-region store next to their Lambda processing pipeline, and regulated workloads where a specific AWS compliance certification is non-negotiable. Outside those two, S3 is not the cheap path in 2026 for a SaaS that serves users over the open internet.
The trap to avoid is the universal default. Picking one of the three for every workload because it is what you already know costs real money once traffic shows up. Storage is plumbing, and the wrong plumbing is invisible until the bill arrives.
Sources
- Cloudflare R2 pricing (Cloudflare Docs)
- R2 S3 API compatibility (Cloudflare Docs)
- Amazon S3 pricing (AWS)
- S3 Intelligent-Tiering (AWS)
- Supabase Storage (Supabase Docs)
- Supabase pricing (Supabase)
- Cloudflare R2 general availability announcement (Cloudflare Blog)
- Super Slurper migration service (Cloudflare Docs)
Frequently asked questions
- Does Cloudflare R2 have hidden costs?
- The egress fee from R2 to the internet is genuinely zero, including through Cloudflare's CDN. The bill comes from operations and from a few overlooked items: $4.50 per million Class A operations (writes, lists, copies), $0.36 per million Class B operations (reads, head), and a minimum monthly storage duration on the Infrequent Access tier if you opt in. For a read-dominated workload, R2 stays cheap. For a high-write workload such as logs or analytics events, the ops cost can rival the storage cost.
- Can I use Supabase Storage and R2 together?
- Yes, and for most SaaS that scale past the Supabase free tier it is the cheapest configuration. Keep auth-scoped, user-private files on Supabase Storage so RLS handles authorisation in one place. Put public or CDN-served media on R2 to avoid the egress bill. The two systems share no native sync, so write your upload pipeline to target one or the other based on the file's audience, not based on convenience.
- What about GDPR and EU data residency?
- Cloudflare R2 lets you pin a bucket to an EU jurisdiction at creation time, which keeps objects within Cloudflare's European data centres. Amazon S3 gives you per-region buckets (eu-west-1, eu-central-1, eu-south-2, and others) and offers explicit BCR plus DPF transfer mechanisms. Supabase projects are pinned to a region at creation and storage objects follow the project region. All three can satisfy GDPR for most SaaS, but the specific certifications you need (SOC 2 Type II, ISO 27001, HIPAA, BSI C5) differ. Check each provider's compliance page against your customer contracts before deciding.
- How risky is migrating from S3 to R2?
- The byte copy itself is low risk thanks to Cloudflare's Super Slurper, which reads from S3 and writes to R2 server-side and pays no egress on Cloudflare's end. The risk lives elsewhere. Any code path that relies on S3-specific features (lifecycle rules, S3 Select, Object Lambda, cross-account replication, presigned URLs longer than 7 days) needs a rewrite before the migration. Run both buckets in parallel for at least one billing cycle, route reads to R2 first with S3 as fallback, and only flip writes once the read traffic looks clean.
Studio
Start a project.
One partner for the digital product you need to build. Faster delivery, modern tech, lower costs. One team, one invoice.