All cheat sheets
Storagecheat sheet

S3 Lifecycle Policies

Automatically move aging S3 objects to cheaper storage classes and delete what expires — often 50%+ off the storage line with one rule. The numbers, the commands, and the gotchas.

Last reviewed: July 11, 2026

TL;DR: Most S3 data is read constantly for a few weeks, then almost never again — while you keep paying the premium S3 Standard rate for it forever. A lifecycle policy moves objects down the storage-class ladder automatically as they age. It's a one-time setup, it runs daily with no code, and on log/backup/archive buckets it routinely cuts the storage line by 50–70%.

The numbers

Storage class $/GB-month (us-east-1) vs Standard
S3 Standard $0.023
S3 Standard-IA $0.0125 −46%
S3 One Zone-IA $0.01 −57%
Glacier Flexible Retrieval $0.0036 −84%
Glacier Deep Archive $0.00099 −96%

Standard-IA and the Glacier tiers charge per-GB retrieval fees and have minimum storage durations (30/90/180 days) — that's the trade you're making for the lower rate.

Do this

  1. Find your biggest buckets. S3 console → Storage Lens (free tier), or CloudWatch BucketSizeBytes. The top three buckets are usually 80% of the bill.

  2. Add the free win first — expire incomplete multipart uploads. Failed uploads leave invisible fragments that bill forever on every bucket:

    aws s3api put-bucket-lifecycle-configuration --bucket YOUR-BUCKET \
      --lifecycle-configuration '{"Rules":[{"ID":"kill-incomplete-mpu",
      "Status":"Enabled","Filter":{},
      "AbortIncompleteMultipartUpload":{"DaysAfterInitiation":7}}]}'
    
  3. Add age-based transitions on buckets with predictable aging (logs, backups, exports):

    aws s3api put-bucket-lifecycle-configuration --bucket YOUR-BUCKET \
      --lifecycle-configuration '{"Rules":[{"ID":"age-out","Status":"Enabled",
      "Filter":{"Prefix":"logs/"},
      "Transitions":[{"Days":30,"StorageClass":"STANDARD_IA"},
                     {"Days":90,"StorageClass":"GLACIER"}],
      "Expiration":{"Days":365}}]}'
    
  4. Not sure how your data is accessed? Turn on S3 Storage Class Analysis or Storage Lens for 30 days and design rules from real access data instead of guesses.

  5. Versioned buckets: add a separate rule for noncurrent versions — old versions are the classic hidden hoard. Archiving noncurrent versions immediately is usually safe.

Gotchas

  • Transitions are one-way. There's no automatic promotion back to Standard; retrieving from Glacier is a manual, per-object restore. Plan the ladder before you build it.
  • Minimum storage durations bite. Glacier Flexible has a 90-day minimum: transition an object and delete it on day 60, and you're billed for 90 days anyway. Don't send short-lived data to Glacier.
  • Small objects can cost more after transition. Each transitioned object carries a per-object request fee plus ~40 KB of metadata overhead in Glacier classes. Under ~128 KB average object size, do the math first.
  • Transition requests aren't free (about $0.01 per 1,000 to IA, more to Glacier). A one-time migration of 100M objects is a real number — spread it or filter by prefix.

Skip this if

  • Your bucket's objects are all short-lived (< 30 days) — expiration alone is fine, transitions won't pay.
  • Access is genuinely unpredictable across all ages — use S3 Intelligent-Tiering instead; it moves objects both directions with no retrieval fees.
  • The bucket is tiny (a few GB) — the savings won't cover the attention.

Run this audit with your AI assistant

Paste this into Claude, ChatGPT, or any agent that can run the AWS CLI with read-only credentials. It audits your account for exactly the waste this sheet describes — and changes nothing.

You are auditing an AWS account for S3 lifecycle-policy savings.
Use the AWS CLI with READ-ONLY credentials. Do not create, modify, or
delete anything — report findings and recommended (unapplied) fixes only.

1. List buckets: aws s3api list-buckets
2. For each bucket (or the 15 largest if there are many), collect:
   - Size per storage class: CloudWatch metric BucketSizeBytes, one query
     per StorageType dimension (StandardStorage, StandardIAStorage, ...).
   - Existing rules: aws s3api get-bucket-lifecycle-configuration
     (a NoSuchLifecycleConfiguration error means "none").
   - Versioning state: aws s3api get-bucket-versioning
   - Stuck incomplete multipart uploads: aws s3api list-multipart-uploads
3. Estimate waste using us-east-1 prices per GB-month: Standard $0.023,
   Standard-IA $0.0125, Glacier Flexible Retrieval $0.0036,
   Glacier Deep Archive $0.00099.

Report a table: bucket | total size | class mix | has lifecycle rules? |
incomplete MPUs | est. $/month saved by a 30d→IA, 90d→Glacier rule.
Then output the top 3 recommended lifecycle configurations as
ready-to-review JSON for put-bucket-lifecycle-configuration — but do NOT
apply them. Flag separately: buckets with average object size under
128 KB (transitions can backfire) and versioned buckets (need separate
noncurrent-version rules).
Works with any assistant that can run shell commands.

Want the guided version?

The S3 Lifecycle Policies walkthrough covers this topic interactively — it asks about your setup, branches to what’s relevant, and quizzes you on the tricky parts. Free and anonymous.

Start the walkthrough