Prerequisites
- An AWS account
- An existing S3 bucket, or the ability to create one
What You'll Learn
- Compare S3 Standard, Standard-IA, Intelligent-Tiering, Glacier, and Deep Archive on cost and retrieval latency
- Write a lifecycle rule that transitions objects between storage classes by age
- Configure a rule that expires objects and incomplete multipart uploads automatically
- Choose the correct storage class for a given access pattern
Theory
S3 charges for three separate things: storage (per GB/month), requests (per GET/PUT), and retrieval (for the colder tiers only). Storage classes trade a lower per-GB storage price for a higher retrieval cost and/or longer retrieval latency — the right choice depends entirely on how often, and how urgently, the data is actually read back.
| Storage class | Retrieval time | Best for |
|---|---|---|
| Standard | Milliseconds | Actively accessed data |
| Intelligent-Tiering | Milliseconds | Unpredictable/unknown access patterns |
| Standard-IA / One Zone-IA | Milliseconds | Infrequent access, but instant when needed |
| Glacier Instant Retrieval | Milliseconds | Archive data rarely read but needed instantly |
| Glacier Flexible Retrieval | Minutes to hours | Archive, retrieval isn't time-critical |
| Glacier Deep Archive | Up to ~12 hours | Long-term compliance archives, rarely if ever read |
Intelligent-Tiering is worth calling out specifically: it monitors each object's access pattern and automatically moves it between frequent and infrequent tiers with no retrieval fee and no performance impact — the right default when you genuinely don't know the access pattern in advance.
Architecture
A typical compliance-log lifecycle: hot for 30 days, cheaper-but-instant for 60 more, deep archive for a year, then deleted
Hands-On Lab
{
"Rules": [
{
"ID": "log-tiering",
"Filter": { "Prefix": "logs/" },
"Status": "Enabled",
"Transitions": [
{ "Days": 30, "StorageClass": "STANDARD_IA" },
{ "Days": 90, "StorageClass": "GLACIER" },
{ "Days": 365, "StorageClass": "DEEP_ARCHIVE" }
],
"Expiration": { "Days": 1825 },
"AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
}
]
}aws s3api put-bucket-lifecycle-configuration \
--bucket my-app-logs \
--lifecycle-configuration file://lifecycle-policy.json
# Verify it applied
aws s3api get-bucket-lifecycle-configuration --bucket my-app-logs
# Check which storage class an object is currently in
aws s3api head-object --bucket my-app-logs --key logs/2026-01-01.log \
--query StorageClassBest Practices
Always set AbortIncompleteMultipartUpload
Failed or abandoned multipart uploads leave orphaned parts that silently accrue storage charges forever unless this rule cleans them up — it costs nothing to enable and has no downside.Use Storage Class Analysis before writing transition rules
S3's built-in Storage Class Analysis observes actual access patterns for 30+ days and recommends transition ages — use it instead of guessing at day thresholds for an existing bucket.Common Mistakes
Transitioning small objects to Glacier
Objects under 128KB aren't worth transitioning — Glacier tiers charge a per-object overhead that can exceed the storage savings for small files. Filter transitions to larger objects, or exclude small-object prefixes.Forgetting IA's per-GB retrieval fee when planning access
Standard-IA and One Zone-IA are cheaper to store but charge a retrieval fee per GB read — a dataset read back frequently despite being tiered to IA can end up costing more than leaving it in Standard. Match the class to actual read frequency, not just age.Troubleshooting
Lifecycle rule isn't transitioning objects:rules only evaluate objects going forward from when the rule was created for age-based transitions in some edge cases with versioning — confirm the rule's Filter (prefix/tag) actually matches the target objects, and note that transitions run as a daily batch process, not instantly at the exact day boundary.
Trying to read a Glacier object returns an error, not data: objects in Glacier Flexible Retrieval or Deep Archive must be explicitly restored first (aws s3api restore-object) before a GET succeeds — a direct GetObject against an un-restored archived object fails with an InvalidObjectState error.
Interview Questions
Frequently Asked Questions
Summary
Choose a storage class based on actual read frequency and urgency, not just object age; Intelligent-Tiering is the safe default for unknown access patterns; lifecycle rules automate transitions and expiration so nobody has to manually tier or delete objects; and Glacier-tier objects require an explicit restore before they can be read.