Cut your egress bill without leaving AWS: the hybrid path
TL;DR. The scariest line on your AWS bill — egress, the per-gigabyte fee to send your own data out to your users — is usually concentrated in one place: object storage (the media, downloads, images and assets you serve from S3). You can cut that line without touching your app, your compute, or your database. Keep everything on AWS, and move only the serving of those files to a zero-egress S3-compatible store (Cloudflare R2, Backblaze B2) — or just put a CDN in front of S3. Keep S3 itself as your source of truth and fallback. It’s reversible, it’s a config change rather than a rewrite, and it captures the single biggest saving for the least risk. Often it’s where I’d start — and sometimes where I’d stop.
You don’t have to leave to stop the bleeding
Most “cut your cloud bill” advice splits into two camps: optimize and stay (squeeze discounts out of AWS) or leave (migrate everything off). There’s a third path that’s lower-risk than either, and it’s the one most teams should try first:
Move the one layer that bleeds — the egress-heavy file serving — and leave everything else exactly where it is.
Your app servers, your database, your queues, your managed services: all stay on AWS, untouched. The only thing that moves is where your users download bytes from. Because that’s where the egress meter runs hardest, moving just that one layer captures most of the savings — with almost none of the risk people associate with “leaving the cloud.”
Why this is the low-risk move (and easy to sign off on)
This is the version a cautious owner, CFO or CTO can approve without losing sleep:
- No app rewrite. The replacement stores all speak the S3 API — your code keeps making the same calls; you change an endpoint and a key, not your application.
- The scary parts don’t move. Compute, database, internal traffic — all stay on AWS. You’re not re-architecting anything load-bearing.
- S3 stays as your source of truth and fallback. Keep the canonical copy in S3. If the cheaper layer ever hiccups, you fall straight back to S3 — you’ve added a cheaper path, not removed your safety net.
- It’s reversible in minutes. Repoint serving back to S3 and you’re exactly where you started. Compare that to a database migration you can’t easily undo.
- You can do it gradually. Serve 10% of traffic from the cheap layer, watch it, then ramp. No big-bang cutover.
That combination — biggest saving, smallest blast radius, fully reversible — is why this is usually the first move, not the last.
The three ways to do it (least effort first)
1. Put a CDN in front of S3 (no data migration at all)
A CDN caches your files at the edge, so repeat requests are served from the cache and never touch S3 egress. Cloudflare’s free tier or bunny.net in front of your existing bucket removes most of the bill without moving a single byte. The only egress you still pay is the occasional cache miss fetching from S3 — small, if your files are cacheable. Lowest-effort option, and a fine place to stop for many sites.
Caveat: this helps for cacheable content (images, video, downloads, static assets). Truly dynamic, per-user responses don’t cache, so a CDN won’t fix egress that comes from your application rather than your files.
2. Mirror S3 to a zero-egress store, serve from there
Keep S3 as the canonical copy, replicate it to a zero-egress S3-compatible store, and point your CDN/app at the copy for serving:
- Cloudflare R2 — S3-compatible, no egress fees at all. You pay for storage and operations, not for bytes served out.
- Backblaze B2 — very cheap storage (~$6/TB); egress is free up to 3× what you store each month, and free with no caps when served through Cloudflare (the Bandwidth Alliance). (Leaving B2 to another cloud still costs normal egress — the free path is Cloudflare-served downloads.)
S3 stays your source of truth; the cheap store is just the cheap serving path. You’ve decoupled “where the canonical data lives” from “where users pull it from” — and only the second one was costing you egress.
3. Migrate gradually, copy-on-read (no cutover)
You don’t have to move everything at once. Cloudflare R2 can pull objects from your S3 bucket on demand: the first time an object is requested from R2 and isn’t there yet, R2 fetches and copies it from S3 automatically (Cloudflare calls this Sippy), with a bulk copy tool (Super Slurper) handling the rest in the background. So your files migrate themselves as they’re used, S3 stays authoritative until each object is copied, and there’s never a flip-the-switch moment.
When the hybrid is enough — and when it isn’t
The hybrid is the right call when:
- Your egress bill is dominated by object storage — media, downloads, images, datasets, backups served to users. (This is the most common shape.)
- You want a reversible, low-risk proof of the savings before committing to anything bigger.
- You’re not ready (or don’t want) to touch compute, database, or the rest of the stack.
It won’t be enough when:
- The egress comes from your application / API responses, not stored files — then you need the serving layer moved (a flat-rate box or a CDN in front of the app), not just a storage swap.
- The big line is steady 24/7 compute rather than bandwidth — a storage move doesn’t touch that. (See optimize vs. leave and open-source AWS alternatives.)
- You’re leaving for data sovereignty or lock-in reasons, not just cost — then the hybrid is a first step, not the destination.
The honest framing: the hybrid move is the wedge. It captures the biggest, easiest saving with the least risk. If that’s all you needed, wonderful — stop there. If more of your bill is still bleeding afterward, you’ve now got a low-stakes proof that the approach works, and you can move the next layer when you’re ready.
Quick wins you can do this week
- Find your egress line and check how much of it is object-storage serving vs. application traffic (group your bill by usage type; see S3 egress cost).
- If it’s cacheable files, put Cloudflare’s free tier or bunny.net in front of the bucket — measure the drop before doing anything else.
- If egress is still high, stand up an R2 or B2 bucket, mirror a slice of your data, and serve it to a small percentage of traffic to prove the saving.
- Keep S3 as the source of truth throughout — you’re adding a cheaper path, not removing your safety net.
Want to know how much of your egress is the easy object-storage kind versus the harder application kind — send me your cloud bill and I’ll break it out and tell you whether the hybrid move alone gets you there, free, in 24 hours. Read by me, never shared. Or see the Cloud-Exit Assessment for the full picture.
Sources
- Egress economics — see S3 egress cost on this site (AWS ~$0.09/GB, unchanged since 2018; sourced from AWS pricing + Cloudflare’s analysis).
- Cloudflare R2 — zero egress fees; Sippy (incremental copy-on-read from an S3 source bucket) and Super Slurper (bulk migration, now generally available) — Cloudflare R2 docs + engineering blog (developers.cloudflare.com/r2/data-migration; blog.cloudflare.com). Confirmed current mid-2026.
- Backblaze B2 — ~$6/TB storage, free egress up to 3× stored data, and unlimited free egress on the Cloudflare-served path (Bandwidth Alliance) — Backblaze + Cloudflare partnership (backblaze.com/blog; cloudflare.com/partners/technology-partners/backblaze). Confirmed current mid-2026.
- CDN in front of S3 — cache hits are served from the edge and don’t incur S3 egress; only cache misses fetch from origin — general CDN behaviour, Cloudflare / bunny.net docs.
- S3-compatible APIs — R2, B2, SeaweedFS and Garage all speak the S3 API, so application code rarely changes — see Migrate off MinIO.