IAnswerable

Cut S3 Costs with Lifecycle Rules

25 Dec 2025

Objects sitting in S3 Standard that nobody has read in six months are pure waste. Lifecycle rules move them to cheaper storage automatically — set it up once, stop thinking about it.

The storage classes that matter

Class Use for Retrieval
Standard Actively accessed data Instant
Standard-IA Accessed monthly, not daily Instant, per-GB retrieval fee
Glacier Instant Retrieval Rarely accessed, needs to load fast when it does Instant, higher retrieval fee than IA
Glacier Flexible Retrieval True archives, occasional access Minutes to hours
Glacier Deep Archive Compliance retention, essentially never read Up to 12 hours

Standard-IA and above are meaningfully cheaper per GB than Standard, but they charge a per-GB retrieval fee on top. That tradeoff only pays off if the object is genuinely accessed rarely — moving frequently-read data to IA to save on storage can cost you more overall once retrieval fees are counted.

Setting up the rule

Console: bucket → Management → Lifecycle rules → Create. Or via CLI with a JSON policy:

{
  "Rules": [
    {
      "ID": "age-out-uploads",
      "Filter": { "Prefix": "uploads/" },
      "Status": "Enabled",
      "Transitions": [
        { "Days": 30, "StorageClass": "STANDARD_IA" },
        { "Days": 90, "StorageClass": "GLACIER" }
      ],
      "Expiration": { "Days": 730 }
    }
  ]
}
aws s3api put-bucket-lifecycle-configuration \
  --bucket my-bucket \
  --lifecycle-configuration file://lifecycle.json

Scope rules with a Prefix filter. Applying one rule to an entire bucket when only one folder’s contents actually age out will misclassify data you still access regularly.

The minimum object size trap

S3 charges a minimum storage duration on IA and Glacier tiers — 30 days for Standard-IA, 90 for Glacier, 180 for Deep Archive. Delete or transition an object before that minimum and you’re still billed as if it sat there the full duration. Don’t set a lifecycle rule that transitions to IA at day 20 and expires at day 25 — you’ll pay the 30-day minimum for nothing.

There’s also a small per-object overhead charge for IA and Glacier transitions, which makes transitioning huge numbers of tiny objects (a few KB each) not worth it — the overhead can exceed the storage savings. Lifecycle rules pay off on larger objects (logs, backups, media files), not a bucket full of small JSON blobs.

Incomplete multipart uploads are a silent cost

Failed or abandoned multipart uploads leave orphaned parts in your bucket that don’t show up in a normal object listing but still bill you. Add this to every bucket, it costs nothing to have and nothing but money to skip:

{
  "Rules": [
    {
      "ID": "clean-incomplete-uploads",
      "Status": "Enabled",
      "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
    }
  ]
}

Check before you commit

Before setting up transitions blind, look at S3 Storage Lens (free tier available in every account) or Storage Class Analysis on the prefix you’re targeting. It tells you actual access patterns over the last 30-90 days, so your transition timing is based on real data instead of a guess about when things go cold.

The actual habit

Set expiration on anything genuinely temporary — build artifacts, upload staging areas, logs past your retention requirement — at creation time, not as cleanup later. A 730-day Expiration rule on a prefix you know is disposable is the single highest-leverage line in this whole setup, because storage that gets deleted costs nothing forever, and storage that just gets cheaper still costs something forever.