The cloud storage cleanup playbook: cutting object and block spend
Storage rarely spikes, it creeps, which is why it is the least audited line on most bills. Here is a five step cleanup covering tier policy, incomplete uploads, versioning, replication, and block storage, with real per GB rates.
Quick answer
Five steps in order. 1) Enable storage analytics and find what is never read. 2) Abort incomplete multipart uploads, invisible in the console but billed at full rate. 3) Expire non-current object versions, which commonly double a versioned bucket's size. 4) Apply lifecycle tiering: S3 Standard at $0.023/GB to Standard-IA at $0.0125, Glacier Instant at $0.004, Deep Archive at $0.00099. 5) Convert gp2 block storage at $0.10/GB-month to gp3 at $0.08 and shrink over-provisioned volumes. Expected result is a 40 to 70 percent reduction in object storage spend and 20 percent on block, with retrieval cost the main risk.
Storage is the quiet line. It never spikes, so no alert fires, and it grows a few percent a month until it is one of the top three items on the bill. The cleanup is mechanical and the savings are durable, provided you understand the two traps: retrieval charges on colder tiers and minimum storage durations that make early deletion more expensive than leaving data where it was.
The per GB rates that drive every decision
| Tier | AWS S3 | Azure Blob | GCS |
|---|---|---|---|
| Hot / Standard | $0.023 | $0.018 | $0.020 |
| Infrequent / Cool | $0.0125 | $0.010 | $0.010 (Nearline) |
| Cold | $0.004 (Glacier IR) | $0.0036 | $0.004 (Coldline) |
| Archive | $0.00099 (Deep Archive) | $0.00099 | $0.0012 |
The spread between hot and archive is roughly 23 to 1. That is why tiering, not deletion, is usually the biggest single lever: you rarely need to delete data if you can move it four cents down per GB.
Step 1: find out what is actually read
Enable storage class analysis or the equivalent access logging before writing any policy. Most buckets show the same shape: the last 30 days of objects account for nearly all reads, and everything older is read almost never. That distribution is what makes tiering safe. Without it you are guessing, and a wrong guess on a hot dataset means retrieval charges that exceed the storage saving.
Step 2: abort incomplete multipart uploads
This is the most overlooked line in object storage. When a large upload fails partway, the parts already uploaded stay in the bucket, bill at full Standard rate, and do not appear in the object listing. Buckets with heavy upload traffic can accumulate terabytes this way. A lifecycle rule aborting incomplete multipart uploads after 7 days costs nothing and sometimes removes 5 to 15 percent of a bucket outright. Do this first because it is free and invisible.
Step 3: deal with versioning
Versioning is a safety feature that doubles storage cost when nobody expires old versions. Every overwrite creates a non-current version billed at full rate, and delete markers hide objects without removing their storage. On a bucket with frequent overwrites, non-current versions are often more than half the total bytes. Add a lifecycle rule that transitions non-current versions to a cheap tier after 30 days and expires them after 90, and clean up expired delete markers. Match the retention window to whatever your recovery requirements genuinely are rather than to what feels safe.
Step 4: apply the tiering policy
With the access distribution in hand, write the lifecycle rule. A typical policy moves objects to infrequent access at 30 days, to a cold tier at 90, and to archive at 365. On 500 TB entirely in S3 Standard, that is about $11,500 a month. With 20 percent staying hot, 30 percent in Standard-IA, 30 percent in Glacier Instant, and 20 percent in Deep Archive, the same data costs roughly $4,600 a month, a 60 percent cut.
The risks are specific and worth stating. Standard-IA has a 30 day minimum billing duration and a per GB retrieval fee, Glacier tiers have 90 and 180 day minimums plus higher retrieval costs, and there is a per object transition charge that makes tiering millions of tiny objects uneconomic. The rule of thumb is that objects under 128 KB should not be transitioned at all. The mechanics are in S3 lifecycle policies and the tier comparison in storage class comparison.
Step 5: block storage
Block storage cleanup has three moves. First, delete unattached volumes, which bill at the full rate while attached to nothing. Second, migrate gp2 volumes to gp3: gp2 is $0.10 per GB-month and gp3 is $0.08 with 3,000 baseline IOPS included, a 20 percent cut with usually better performance, and the migration is a live modification with no downtime. On 200 TB of gp2 that is about $4,000 a month saved. Third, shrink volumes provisioned far above their used capacity, noting that most clouds cannot shrink a volume in place, so this means creating a smaller volume and migrating data.
Also check replication and cross region copies
Cross region replication doubles storage cost and adds inter region transfer charges on every write. Audit which buckets replicate and whether the destination is still needed; replication configured for a disaster recovery plan that changed two years ago is common. Similarly, check whether you are paying for a redundancy level you do not need, such as geo redundant storage on non-production data.
Expected outcome
A full pass typically cuts object storage spend 40 to 70 percent and block storage 20 to 30 percent. Unlike compute optimisation, these savings persist because lifecycle policies keep working on data that has not been written yet. The ongoing discipline is to set the lifecycle rule in the Terraform that creates the bucket rather than after the fact, and to price storage configurations against the resource catalog before they ship.
FAQ
What is the biggest object storage saving?
Tiering, not deletion. The spread between hot storage at about $0.023 per GB-month on S3 Standard and archive at about $0.00099 on Deep Archive is roughly 23 to 1, so moving cold data down a tier usually beats deleting it. A typical policy moving objects to infrequent access at 30 days, cold at 90, and archive at 365 cuts a large bucket's cost by around 60 percent.
What are incomplete multipart uploads costing me?
Potentially 5 to 15 percent of a bucket. When a large upload fails partway, the uploaded parts stay in the bucket, bill at the full Standard rate, and do not appear in the object listing, so they are invisible in the console. A lifecycle rule aborting incomplete multipart uploads after 7 days costs nothing to implement and should be the first step of any storage cleanup.
How does versioning affect storage cost?
It commonly doubles it. Every overwrite creates a non-current version billed at the full rate, and delete markers hide objects without removing their storage. On buckets with frequent overwrites, non-current versions are often more than half the total bytes. Add a lifecycle rule transitioning non-current versions to a cheap tier after 30 days and expiring them after 90.
What are the risks of moving data to colder storage tiers?
Minimum storage durations and retrieval fees. Standard-IA has a 30 day minimum billing duration plus a per GB retrieval fee, and Glacier tiers have 90 and 180 day minimums with higher retrieval costs, so data deleted or read early costs more than leaving it hot. There is also a per object transition charge, which makes tiering objects under about 128 KB uneconomic.
Should I migrate EBS gp2 volumes to gp3?
Almost always. gp2 is $0.10 per GB-month and gp3 is $0.08 with 3,000 baseline IOPS and 125 MB/s throughput included, so it is a 20 percent cut with usually better and more predictable performance. The migration is a live volume modification with no downtime. On 200 TB of gp2 that is about $4,000 a month for a change that takes an afternoon to script.
Does storage cleanup stay saved?
More than compute optimisation does, because lifecycle policies keep applying to data that has not been written yet. The gap is new buckets and volumes created without policies attached. Set the lifecycle rule in the Terraform that creates the bucket rather than adding it later, and price storage configurations before they ship so a geo redundant non-production bucket is caught at review.
What to do next
Set the lifecycle policy before the bucket exists. C3X prices storage from Terraform against a live resource catalog. Start with the quickstart.
Share this post
Try C3X on your own Terraform
Free and open source. No API key required. One command to install, one command to estimate.