I once watched a team move 40 TB to S3 Glacier Deep Archive to "save money," then expedite-restore half of it the next month for an audit. The restore and retrieval fees erased a year of storage savings. S3 storage classes only save money when you match them to a real access pattern, and the pricing has more moving parts than the per-GB number everyone quotes.

This is how I actually reason about the classes, with the costs that bite you.

The per-GB price is only one of four costs

Every object in S3 has up to four cost dimensions. People compare column one and ignore the rest.

  • Storage, per GB-month. The headline number.
  • Requests, PUT/GET per 1,000. Cold classes charge more per request.
  • Retrieval, per GB to read data out of the colder classes. Standard and Intelligent-Tiering have none.
  • Minimum duration, delete early and you still pay for the minimum (30/90/180 days depending on class).

What each class actually costs (us-east-1, approx)

ClassStorage $/GB-moRetrievalMin durationUse when
Standard0.023nonenoneHot, frequently read data
Standard-IA0.0125$0.01/GB30 daysAccessed monthly, not daily
One Zone-IA0.01$0.01/GB30 daysReproducible data, single-AZ OK
Glacier Instant Retrieval0.004$0.03/GB90 daysArchive read milliseconds, rarely
Glacier Flexible Retrieval0.0036$0.01/GB + per-request90 daysMinutes-to-hours retrieval OK
Glacier Deep Archive0.00099$0.02/GB, 12h restore180 daysCompliance, almost never read

Notice Standard-IA is roughly half the storage cost of Standard but adds a retrieval fee and a 30-day floor. If you read an object more than about once a month, IA costs more than Standard once retrieval is included.

When you don't know the pattern, use Intelligent-Tiering

For data with unpredictable or unknown access, S3 Intelligent-Tiering is usually the right default. It moves objects between frequent, infrequent, and (optionally) archive tiers automatically based on access, with no retrieval fees in the instant tiers. The cost is a small monitoring charge per object (~$0.0025 per 1,000 objects/month).

That per-object monitoring fee is why Intelligent-Tiering is a bad fit for millions of tiny objects. For 50 KB log lines, the monitoring charge can dwarf the storage saving. It shines on larger objects where access is genuinely uncertain.

Automate transitions with lifecycle rules

For predictable data, logs, backups, media you know cools off, explicit lifecycle rules beat Intelligent-Tiering because you skip the monitoring fee. Here's a rule that ages log objects through the tiers and expires them at two years.

aws s3api put-bucket-lifecycle-configuration \
  --bucket my-app-logs \
  --lifecycle-configuration '{
    "Rules": [{
      "ID": "age-out-logs",
      "Filter": { "Prefix": "logs/" },
      "Status": "Enabled",
      "Transitions": [
        { "Days": 30,  "StorageClass": "STANDARD_IA" },
        { "Days": 90,  "StorageClass": "GLACIER" },
        { "Days": 365, "StorageClass": "DEEP_ARCHIVE" }
      ],
      "Expiration": { "Days": 730 }
    }]
  }'

One caveat that surprises people: transitioning an object to a colder class is itself a charged request. Transitioning millions of small objects can cost more in transition requests than you save in storage. The fix is to set a minimum object size filter or aggregate small files before they land.

How I decide in practice

  1. Read often (daily-ish)? Stay on Standard.
  2. Access pattern unknown and objects > 128 KB? Intelligent-Tiering.
  3. Known cooldown curve? Explicit lifecycle rules through IA → Glacier.
  4. Compliance copy you'll basically never read? Deep Archive, and budget for the 12-hour restore.

Takeaways

  • Compare all four cost dimensions, storage, requests, retrieval, minimum duration, not just per-GB.
  • Colder isn't always cheaper: retrieval fees and minimum-duration floors can flip the math entirely.
  • Use Intelligent-Tiering for unknown patterns on larger objects; lifecycle rules for known cooldowns.
  • Watch transition and monitoring fees on huge counts of tiny objects, aggregate them first.