How to Reduce S3 Storage Costs: 3 Levers That Still Work
How to reduce S3 storage costs when S3 Standard has stayed $0.023/GB-month since 2016: storage-class tiering, free-egress R2, and Glacier's deletion-fee traps.

TL;DR Here’s how to reduce S3 storage costs even though AWS hasn’t cut them: S3 Standard is $0.023 per GB-month, unchanged since December 2016. The savings instead come from tiering cold data into Standard-IA and Glacier (Glacier Instant Retrieval saves up to 68% over Standard-IA, by AWS’s own figure) and from killing egress fees on internet-facing buckets by routing them through Cloudflare R2, which charges $0 to send data out versus S3’s $0.09/GB. Respect Glacier’s 30/90/180-day minimum-storage windows too, or an early deletion erases the savings you just made.
In September 2026, a Hacker News thread pointed out something most engineers had stopped noticing: Amazon S3’s headline storage price hasn’t moved in ten years. From 2006 to 2014, AWS cut S3 Standard repeatedly, from $0.150 down to $0.085 per GB-month. Between 2014 and 2016 it dropped again, to today’s $0.023. Then it froze.
A decade of Moore’s Law, cheaper disks, and falling bandwidth costs across the industry, and the number on your AWS bill for storing a gigabyte hasn’t changed since the month the iPhone 7 shipped. AWS has never explained why — the practical read is that S3’s durability guarantees and deep integration with the rest of AWS (Lambda triggers, Athena, Glue, IAM) make it sticky enough that price competition doesn’t reach it the way it reaches raw compute. Whatever the reason, waiting for AWS to lower the price is not a cost strategy. The three levers below are.
What does S3 storage actually cost in 2026?
S3 Standard is $0.023 per GB-month in US East (N. Virginia), unchanged since December 2016. That number is the baseline every other lever in this post measures against. On top of storage, AWS bills data transfer out to the internet in declining tiers: $0.09/GB for the first 10 TB each month, $0.085/GB for the next 40 TB, $0.06/GB for the next 100 TB, and $0.04/GB for the next 350 TB. For a bucket that stores data and rarely serves it directly — a data lake feeding Athena queries, say — storage is the whole bill. For a bucket serving images, video, or downloads straight to users, egress usually dwarfs storage within the first few terabytes of monthly traffic.
The freeze matters because most cost-optimization advice from 2016-2020 assumed prices would keep drifting down on their own, the way EC2 and Lambda pricing periodically has. S3 storage didn’t. Every dollar you’re not spending has to come from how you use the service, not from AWS’s price list.
How do S3 storage classes cut your bill?
The lever AWS does give you is storage class. Moving an object out of Standard doesn’t change what it costs to store per se — it changes which class’s pricing and access guarantees apply to it, and the cheaper classes trade retrieval speed or a minimum commitment for a lower rate:
| Storage class | Cost vs. S3 Standard | Minimum storage duration | Retrieval time |
|---|---|---|---|
| S3 Standard | Baseline: $0.023/GB-month | None | Milliseconds |
| S3 Standard-IA / One Zone-IA | Lower per-GB rate, plus a per-GB retrieval fee | 30 days | Milliseconds |
| S3 Glacier Instant Retrieval | Up to 68% less than Standard-IA (AWS’s own figure) | 90 days | Milliseconds |
| S3 Glacier Flexible Retrieval | Up to 10% less than Glacier Instant Retrieval | 90 days | Minutes to hours |
| S3 Glacier Deep Archive | AWS’s lowest-cost S3 tier | 180 days | Hours |
Read that table by access pattern, not by price alone. Standard-IA and Glacier Instant Retrieval both still return objects in milliseconds — the cost saving is real with zero latency penalty, which is why they’re the two tiers worth defaulting to for anything you’re not actively serving. Glacier Flexible Retrieval and Deep Archive only make sense for data you can genuinely wait hours for: compliance archives, old backups, anything a human requests rarely enough that a retrieval job is acceptable.
How to Reduce S3 Storage Costs With a 5-Step Lifecycle Policy
This is the change that requires no application code, only bucket configuration, and it’s the highest-leverage thing most teams haven’t done:
Find your access pattern before you write a rule. Turn on S3 Storage Lens (free at the bucket level) or query CloudTrail data events for a week to see which prefixes are actually being read, and how old the objects are when they’re last touched.
Write a lifecycle rule transitioning to Standard-IA at 30 days. Target objects your Storage Lens data shows aren’t read in the first month — logs, generated reports, upload originals once a processed copy exists.
Add a second transition to Glacier Instant Retrieval at 90 days. Because retrieval is still millisecond-speed, this tier is nearly free to add once the 30-day rule already exists, and it captures the up-to-68% saving over Standard-IA for anything that’s aged past three months untouched.
Exclude anything with an unpredictable delete schedule. Objects that might be deleted before their tier’s minimum duration cost more in early-deletion charges than they save — keep those in Standard or Standard-IA only.
Re-check with Storage Lens or Cost Explorer after 30 days. Lifecycle transitions aren’t retroactive on savings you can predict from a spreadsheet — confirm the byte counts actually moved and the bill actually dropped before tuning the thresholds further.
What breaks if you ignore Glacier’s minimum storage duration?
You pay for storage you no longer have. Glacier Instant Retrieval and Glacier Flexible Retrieval both carry a 90-day minimum storage duration; Glacier Deep Archive carries 180 days. Delete or overwrite an object before that window closes and AWS still bills you for the remaining days at that tier’s rate — a Deep Archive object deleted after 10 days still owes 170 more days of storage charges.
This is the single most common way a well-intentioned lifecycle policy backfires: teams tier data by age without checking whether that data type also gets deleted early for unrelated reasons (a customer closes their account, a retention policy purges records, a bug reprocesses and replaces files). Audit your deletion paths against your tiering rules before you ship them, not after the first surprising invoice line.
How does Cloudflare R2 compare to S3 for egress-heavy workloads?
Storage-class tiering only touches the storage line. For buckets that serve data directly to users, egress is usually the bigger number, and it’s the one lever AWS’s own pricing doesn’t offer a fix for — only a competitor does.
| S3 Standard | Cloudflare R2 Standard | |
|---|---|---|
| Storage | $0.023/GB-month | $0.015/GB-month (about 35% less) |
| Egress to internet | $0.09/GB (first 10 TB/month) | $0 — free |
| Class A operations (writes/lists) | Varies by request type | $4.50 per million |
| Class B operations (reads) | Varies by request type | $0.36 per million |
| API compatibility | Native S3 API | S3-compatible API |
R2’s storage price alone is roughly 35% below S3 Standard, but the number that actually moves a bill is egress: R2 charges nothing to send data to the internet, including through its S3-compatible API, while S3’s first 10 TB/month of egress costs $0.09 per GB. For a bucket serving images, downloads, or API responses directly to users, that difference compounds every month traffic grows — a bucket that’s cheap to store in but expensive to serve from is still an expensive bucket.
Because R2 speaks the S3 API, moving a specific bucket over is often closer to a config and credentials change than a rewrite, which is why the common pattern isn’t “replace S3” but “keep S3 for AWS-side processing, put R2 in front of anything served to the public internet.”
Common mistakes when tuning S3 costs
Tiering data that gets deleted early. As covered above, a lifecycle rule that ignores your delete paths turns a savings feature into an early-termination fee generator.
Turning on Intelligent-Tiering for a bucket with predictable access. Intelligent-Tiering earns its per-object monitoring fee when access patterns are genuinely unpredictable. If Storage Lens already shows a clean age-based pattern, a manual lifecycle rule is usually cheaper — you’re paying for automation you don’t need.
Chasing storage savings while ignoring egress. Tiering can shave 30-60% off a storage line that’s a fraction of the total bill if the bucket serves heavy internet traffic. Check Cost Explorer’s breakdown by usage type before optimizing the smaller number.
Assuming R2 is a drop-in replacement everywhere. R2’s S3-compatible API covers the common operations, but AWS-native integrations — Lambda event triggers, S3 Select, some Glue connectors — don’t have R2 equivalents. Route the internet-facing traffic there; keep AWS-native processing on S3 until you’ve verified the equivalent exists.
The takeaway
Ten years without a price cut on the industry’s default object store is not a reason to accept your current bill — it’s a reason to stop waiting on AWS and start controlling the three things you can: which tier your data sits in, how much of it leaves the network, and whether you’re respecting the minimum-duration windows that make cheap tiers cheap. None of the three levers here require a rewrite. A lifecycle policy is a bucket setting. Routing egress-heavy traffic through R2 is a credentials and endpoint change behind an S3-compatible API. The only real cost is the week it takes to look at Storage Lens data before you write the rule.
If you’re running this alongside other Cloudflare infrastructure, the access-control model matters just as much as the pricing — see how to scope AI agent access to Cloudflare Workers before you wire an automated pipeline into a new R2 bucket, and how to run CI/CD on Cloudflare Workflows if that pipeline needs to run the lifecycle audit on a schedule.
For teams migrating data between stores rather than just re-tiering it, the safety rules in zero-downtime database migration with dual writes and Postgres migration safety and table locks apply just as much to an object-storage cutover as they do to a database one — and if the reason you’re touching storage costs at all is a broader capacity problem, rebalancing shards across servers is usually the adjacent fix worth checking first.
FAQ
Why hasn’t S3 storage pricing dropped since 2016? AWS has not published a reason. S3 Standard fell from $0.150 to $0.023 per GB-month between 2006 and 2016, then held at $0.023 for the following decade despite falling hardware and bandwidth costs industry-wide — likely because S3’s durability guarantees and deep AWS integration make it sticky enough to avoid the price pressure that hits raw compute.
What’s the fastest way to cut an S3 bill without migrating anything? Turn on a lifecycle policy transitioning objects untouched for 30 days to Standard-IA and objects untouched for 90 days to Glacier Instant Retrieval. Both retrieve in milliseconds, so nothing about read latency changes — only bucket configuration.
Is Cloudflare R2 actually cheaper than S3? Storage-wise, yes — $0.015/GB-month versus $0.023, about 35% less. The bigger gap is egress: R2 charges $0 to send data to the internet while S3 charges $0.09/GB for the first 10 TB monthly, which usually matters more for buckets serving traffic directly.
What happens if I delete a Glacier object before its minimum storage duration? You still pay for the unused remainder. Glacier Instant/Flexible Retrieval bill a 90-day minimum and Deep Archive bills 180 days, so an object deleted early still owes the rest of that window at the tier’s rate.
Does S3 Intelligent-Tiering replace the need for a lifecycle policy? It automates the tiering decision but adds a per-object monitoring fee in exchange. For buckets with predictable, age-based access patterns, a manual lifecycle rule is often cheaper than paying that fee across thousands of objects.
Can I mix S3 and R2 in the same architecture? Yes — a common pattern keeps S3 for AWS-native processing (Lambda triggers, Athena, Glue) and puts R2 in front of anything served directly to the public internet, since R2’s S3-compatible API makes the migration closer to a config change than a rewrite.
Sources
- S3 Is the Future, S3 Is the Past — Simon Willison, September 27, 2026. The price-history data point this post is built around: S3 Standard’s decade-long freeze at $0.023/GB-month since December 2016.
- Amazon S3 pricing — AWS. Data-transfer-out tiers ($0.09/GB first 10 TB, declining through $0.04/GB).
- Amazon S3 storage classes — AWS. Minimum storage durations (30/90/180 days) and the “up to 68%” / “up to 10%” relative savings figures for Glacier Instant Retrieval and Glacier Flexible Retrieval.
- Cloudflare R2 pricing — Cloudflare. R2 Standard storage, Class A/B operation pricing, and the zero-egress confirmation.
Frequently asked questions
Google Search · Preferred sources
Prefer this site on Google
If you already read this writing, add umesh-malik.com as a Preferred Source. Google can then highlight it with a preferred badge in Top Stories, AI Overviews, and AI Mode — for you, not as a site-wide ranking boost.
Related Articles

Web Engineering
Docker Swarm vs Kubernetes: $166/yr Beats a $200K Cluster
Docker Swarm vs Kubernetes: a live SaaS runs for $166/year with zero crashes in 10 years, while the average Kubernetes cluster wastes 87% of its CPU.

Web Engineering
Is Your Postgres Migration Safe? Catch the Table Lock First
Is your Postgres migration safe? Not if it takes ACCESS EXCLUSIVE on a hot table. The lock table and 5-step check that catches it before you run it.

Web Engineering
Fix Performance Regressions With a Benchmark Ratchet (3.1x, 0 Breaks)
Fix performance regressions with a benchmark ratchet that fails CI on regression and locks in wins. How Claude shipped 3,000 changes at 3.1x, zero breaks.
Keep reading
Get new posts on AI, Claude Code & LLMs
New deep-dives on AI engineering, Claude Code, and developer tooling — follow along however you prefer.
About the Author
Software engineer writing about AI, Claude Code, LLMs, OpenAI, Anthropic, and developer tooling. 5+ years building production systems at Expedia Group, Tekion, and BYJU'S.