Updated October 3, 2026

Guides · S3

S3 storage costs: storage classes, lifecycle rules and hidden charges

In US East (N. Virginia), S3 Standard costs $0.023 per GB-month for the first 50 TB. Three things quietly add to it: data in Standard that nobody reads, parts of multipart uploads that never finished, and old versions of objects in versioned buckets. All three are billed as storage, and lifecycle rules can deal with all three. The cheaper storage classes have catches, though: minimum storage durations, per-object fees and retrieval charges.

Storage classes and prices (us-east-1)

Storage classStorage, per GB-monthMinimum storage durationMinimum billable object sizeRetrieval, per GB
S3 Standard$0.023 (first 50 TB)
$0.022 (next 450 TB)
$0.021 (over 500 TB)
NoneNoneNone
S3 Intelligent-Tiering$0.023 / $0.0125 / $0.004 by access tier, plus $0.0025 per 1,000 monitored objectsNoneNoneNone
S3 Standard-IA$0.012530 days128 KB$0.01
S3 One Zone-IA$0.0130 days128 KB$0.01
S3 Glacier Instant Retrieval$0.00490 days128 KB$0.03
S3 Glacier Flexible Retrieval$0.003690 days40 KB added per object$0.01 standard, free bulk
S3 Glacier Deep Archive$0.00099180 days40 KB added per object$0.02 standard, $0.0025 bulk

Lifecycle rules: moving and deleting data automatically

A lifecycle configuration is a set of rules on a bucket. Each rule picks objects (by prefix, tag or size) and either moves them to a cheaper class after a number of days (a transition) or deletes them (an expiration). Rules apply to objects already in the bucket as well as new ones. Expirations are free: you aren't charged for the expiration or for storage after an object expires.

Transitions are not free. Each object moved is one request:

Transition intoPer 1,000 objects
Standard-IA, One Zone-IA or Intelligent-Tiering$0.01
Glacier Instant Retrieval$0.02
Glacier Flexible Retrieval$0.03
Glacier Deep Archive$0.05

That's why the object count matters as much as the size. Take 1,000 GB stored as one million 1 MB objects:

Where it's storedStorage per monthOne-time transitionReading it all back once
S3 Standard$23.00$0.40 in GET requests
S3 Standard-IA$12.50$10$10 retrieval + $1 in GET requests
S3 Glacier Instant Retrieval$4.00$20$30 retrieval + $10 in GET requests
S3 Glacier Deep Archive$0.99 + about $0.22 overhead$50$20 retrieval + $100 in restore requests, plus Standard storage for the restored copies

If the same 1,000 GB were 100 million 10 KB objects, moving them to Standard-IA would cost $1,000 in transition requests, and each object would then be billed as 128 KB. That's why, by default, lifecycle rules don't transition objects smaller than 128 KB. Objects that are read often belong in Standard; colder classes pay off for data that's rarely read and kept past the minimum duration.

Incomplete multipart uploads

Large files are often uploaded in parts. Until the upload is completed or stopped, S3 keeps every part and bills it as storage in the class the upload was headed for. A failed or abandoned upload can leave parts in the bucket indefinitely. They aren't objects, so look for them with list-multipart-uploads or Storage Lens rather than an object listing. They do count in the bucket's size.

AWS recommends a lifecycle rule with the AbortIncompleteMultipartUpload action as a best practice. It stops uploads that haven't completed within a set number of days after they started, and deletes their parts. It doesn't touch completed objects, and deleting the parts has no early-deletion charge in any storage class.

Old versions in versioned buckets

With versioning on, overwriting an object keeps the old one as a noncurrent version, and deleting an object only adds a delete marker. Every version is a full copy, billed at normal rates: three versions of a 1 GB file is 3 GB of storage. An expiration rule on a versioned bucket doesn't delete anything either; it makes the current version noncurrent.

To remove old versions, use the NoncurrentVersionExpiration action. It permanently deletes versions a set number of days after they became noncurrent, and can keep a number of the newest noncurrent versions (1 to 100) regardless of age. Deleted versions can't be recovered, so decide how far back you need to be able to restore first. The ExpiredObjectDeleteMarker option cleans up delete markers that have no versions left behind them.

Intelligent-Tiering and its monitoring fee

Intelligent-Tiering moves each object between access tiers based on when it was last read: to Infrequent Access ($0.0125) after 30 days without access, and to Archive Instant Access ($0.004) after 90 days. Reading an object moves it back to Frequent Access ($0.023). There are no retrieval fees. Two archive tiers are optional: Archive Access ($0.0036, after at least 90 days) and Deep Archive Access ($0.00099, after at least 180 days). Objects in those must be restored before reading: a standard restore takes 3 to 5 hours from Archive Access and up to 12 hours from Deep Archive Access.

The catch is the monitoring and automation fee: $0.0025 per 1,000 objects a month. Objects smaller than 128 KB aren't monitored, aren't charged the fee, and always stay in Frequent Access. For the rest, the fee is per object, while the saving is per GB:

Intelligent-Tiering suits buckets of larger objects with unknown or changing access patterns. For millions of small objects, or data that's read constantly, it can cost more than Standard.

Check it yourself

1. What S3 costs you: Billing and Cost Management → Cost Explorer, filtered to S3 and grouped by Usage type. Usage types ending in TimedStorage-ByteHrs are Standard storage, TimedStorage-SIA-ByteHrs Standard-IA and Monitoring-Automation-INT the Intelligent-Tiering monitoring fee. Usage types containing EarlyDelete are minimum-duration charges.

2. Old versions and stale uploads across the account: S3 console → Storage Lens → the default dashboard (default-account-dashboard). Its free metrics include Noncurrent version bytes and Incomplete multipart upload storage bytes greater than 7 days old.

3. One bucket (read-only commands):

# lifecycle rules, if any, and whether versioning is on
aws s3api get-bucket-lifecycle-configuration --bucket my-bucket
aws s3api get-bucket-versioning --bucket my-bucket

# multipart uploads that were started and never completed or stopped
aws s3api list-multipart-uploads --bucket my-bucket \
  --query 'Uploads[].[Key,Initiated]' --output table

# bytes in Standard, from CloudWatch's daily storage metric (use the bucket's region)
aws cloudwatch get-metric-statistics --region us-east-1 --namespace AWS/S3 \
  --metric-name BucketSizeBytes \
  --dimensions Name=BucketName,Value=my-bucket Name=StorageType,Value=StandardStorage \
  --start-time 2026-09-30T00:00:00Z --end-time 2026-10-03T00:00:00Z \
  --period 86400 --statistics Average --output table

BucketSizeBytes includes noncurrent versions and the parts of incomplete multipart uploads, so it can be larger than the total of the objects you can see. Other StorageType values include StandardIAStorage, GlacierInstantRetrievalStorage and IntelligentTieringFAStorage.

Adding the rules

Console: open the bucket → Management → Create lifecycle rule. Or with the CLI. This example aborts multipart uploads still incomplete after 7 days, deletes noncurrent versions 30 days after they become noncurrent while keeping the newest 3, and moves objects under logs/ to Standard-IA after 30 days. The numbers are examples; choose your own.

{
  "Rules": [
    { "ID": "abort-incomplete-uploads", "Status": "Enabled", "Filter": { "Prefix": "" },
      "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 } },
    { "ID": "expire-noncurrent-versions", "Status": "Enabled", "Filter": { "Prefix": "" },
      "NoncurrentVersionExpiration": { "NoncurrentDays": 30, "NewerNoncurrentVersions": 3 } },
    { "ID": "logs-to-standard-ia", "Status": "Enabled", "Filter": { "Prefix": "logs/" },
      "Transitions": [ { "Days": 30, "StorageClass": "STANDARD_IA" } ] }
  ]
}

Then (this one changes your bucket):

aws s3api put-bucket-lifecycle-configuration --bucket my-bucket \
  --lifecycle-configuration file://lifecycle.json

This replaces the bucket's whole lifecycle configuration. If the bucket already has rules, copy them into the file first, or they'll be lost. A version is only deleted once it's both older than NoncurrentDays and beyond the NewerNoncurrentVersions count.

The free checkup finds this and 20 other kinds of issues automatically. For S3 it checks one thing. For each bucket (up to 300), it reads whether the bucket has a lifecycle configuration and how many bytes it holds in S3 Standard, from CloudWatch's daily storage metric. It lists Standard buckets of 100 GB or more that have no lifecycle configuration at all, and estimates the saving at 20% of their Standard storage cost ($0.023 per GB-month, roughly adjusted for the bucket's region), marked low confidence. It doesn't look inside a lifecycle configuration, so a bucket with any rule passes. It doesn't separately measure incomplete multipart uploads, noncurrent versions, other storage classes, the Intelligent-Tiering monitoring fee, or request and retrieval charges. It never reads your objects.

Run a free checkup

Sources

Prices are AWS list prices for US East (N. Virginia), checked October 3, 2026. Other regions differ. Examples use 1 GB = 1,000 MB for simplicity.