Key takeaways
- Standard storage costs $0.023 per GB-month; the archive tiers run as low as $0.00099, a 96 percent drop
- Most buckets never get a lifecycle policy because the default works and nobody owns storage class decisions
- Noncurrent versions and abandoned multipart uploads are the two rules every bucket should have, even hot ones
- Minimum storage durations and per-object transition fees can reverse the savings on small or short-lived objects
S3 charges by the gigabyte-month, and the gap between its storage classes is enormous: Standard costs $0.023 per GB-month in us-east-1, while Glacier Deep Archive costs $0.00099 for the same durability. A lifecycle policy is the mechanism that moves objects down that ladder automatically. Buckets without one pay the Standard rate on every byte forever, including logs nobody has read since the week they were written.
The rules themselves are a few lines of configuration. The work is knowing which buckets need them, which class each dataset belongs in, and which fine print can turn a well-meaning rule into a bigger bill. This guide walks through the whole sequence, from finding the buckets to verifying the savings landed.
Find the buckets paying Standard rates for cold data
TimedStorage-ByteHrs is Standard storage, and the equivalents for the other classes carry their own usage types (TimedStorage-SIA-ByteHrs for Standard-IA, TimedStorage-GIR-ByteHrs for Glacier Instant, and so on). A bill that is overwhelmingly TimedStorage-ByteHrs in an account holding years of logs, backups, or exports is the signature of missing lifecycle policies.Then check which buckets actually have policies. There is no console view that lists lifecycle coverage across buckets, which is a big part of why the gap persists, but a short script gets you there:
for b in $(aws s3api list-buckets --query 'Buckets[].Name' --output text); do
aws s3api get-bucket-lifecycle-configuration --bucket "$b" \
--query 'Rules[].ID' --output text 2>/dev/null \
|| echo "NO LIFECYCLE: $b"
done
BucketSizeBytes CloudWatch metric) and work from the largest down. One 200 TB log bucket matters more than forty small ones.Match each bucket's data to a storage class
| Class | Price per GB-month | Built for |
|---|---|---|
| Standard | $0.023 | Data read routinely |
| Standard-IA | $0.0125 | Read less than monthly, needed instantly |
| Glacier Instant Retrieval | $0.004 | Read rarely (quarterly or less), needed instantly |
| Glacier Flexible Retrieval | $0.0036 | Restores can wait minutes to hours |
| Glacier Deep Archive | $0.00099 | Compliance archives; restores can wait 12 hours |
The pattern to internalize: the infrequent-access classes keep millisecond reads and charge a per-GB retrieval fee instead ($0.01 per GB from Standard-IA), while the deeper Glacier tiers make you wait for restores. The ladder maps neatly onto household storage: Standard is the closet you reach into weekly, the IA classes are the attic, and Deep Archive is the offsite unit you rent because the rules say you must keep the boxes. Ask of each dataset: how often is it read, and when it is read, how fast does it need to arrive? Application logs might sit in Standard for 30 days while anyone still debugs against them, then step down to Standard-IA, then to a Glacier tier once the only remaining reader is an auditor.
Write the rules, including the two everyone forgets
A lifecycle configuration attaches to the bucket and runs daily with no compute of yours involved. A typical progression for a log bucket:
{
"Rules": [
{
"ID": "age-out-logs",
"Filter": { "Prefix": "logs/" },
"Status": "Enabled",
"Transitions": [
{ "Days": 30, "StorageClass": "STANDARD_IA" },
{ "Days": 90, "StorageClass": "GLACIER_IR" },
{ "Days": 365, "StorageClass": "DEEP_ARCHIVE" }
],
"Expiration": { "Days": 2555 }
}
]
}
Two more rules belong in nearly every bucket, including ones whose live data must stay hot:
NoncurrentVersionTransition or NoncurrentVersionExpiration rule caps how long those superseded copies live. Versioned buckets without one routinely store several old bytes for every current byte.AbortIncompleteMultipartUpload after 7 days cleans them up automatically. This rule has no downside and belongs on every bucket in the account.Use Intelligent-Tiering when you cannot predict the pattern
If a bucket's access pattern is genuinely unknown, or different objects in it behave differently, S3 Intelligent-Tiering makes the class decision per object. It watches each object and moves anything untouched for 30 days to an infrequent-access tier priced like Standard-IA, then after 90 days to an archive-instant tier priced like Glacier Instant, moving objects back up the moment they are read. There are no retrieval fees between the automatic tiers; the cost is a monitoring fee of $0.0025 per 1,000 objects per month.
That per-object fee is the deciding variable. On buckets full of large objects the fee is noise and Intelligent-Tiering is close to a free option. On buckets holding hundreds of millions of tiny objects, the monitoring fee can exceed what tiering saves, and a prefix-based lifecycle rule you wrote yourself does better. As a rule of thumb, objects need to average above roughly 1 MB before Intelligent-Tiering is comfortably ahead for unpredictable data.
Check the fine print before you flip it on
Three mechanisms can claw back the savings, and all three are avoidable once you know they exist:
Verify the savings landed
TimedStorage-ByteHrs line starts falling and the destination class's usage type starts growing. Check Cost Explorer after the first week, and again after the first full month, comparing total S3 spend for the bucket against the pre-policy baseline. The first month will also carry the one-time transition request charges, so judge the steady state from month two.If a rule seems to be doing nothing, the usual causes are a filter prefix that does not match the real key layout, or versioning: transitions on a versioned bucket apply to current versions, and the noncurrent copies need their own rule. S3 Storage Lens shows per-bucket, per-class byte counts that settle the question in one screen.



