A storage class changes retrieval behavior, resilience, and billing, not just the monthly price of bytes. Start with the time allowed to recover data and whether another copy can be recreated. Standard-IA offers immediate access with retrieval charges; Glacier Flexible Retrieval and Deep Archive require restoration before ordinary reads. One Zone-IA also has a different failure boundary: its data is not resilient to physical loss of its Availability Zone.
Separate the charges before comparing totals
Use the current price sheet for the bucket’s Region and the exact class, retrieval tier, and request type. Storage is charged by billable capacity and duration; retrieval can be charged by bytes, requests, or both. Per-object transitions and archive metadata scale with object count. It is incorrect to describe all these costs as driven only by object count, or to infer total savings from one storage rate.
Do not treat standard retrieval from Flexible Retrieval and Deep Archive as universally free. The price sheet checked on 2026-10-18 lists Flexible Retrieval bulk retrievals and requests as free; Intelligent-Tiering has separate free standard and bulk retrieval rules. Those exceptions do not establish the same price for another class or tier. A restored archive also retains the archived object while its temporary readable copy incurs Standard storage charges for the chosen lifetime.
Minimum durations matter even when an object disappears sooner: Standard-IA and One Zone-IA use thirty days, Glacier Instant and Flexible Retrieval ninety, and Deep Archive 180. Early deletion, replacement, or transition can incur the remaining minimum charge. Standard-IA, One Zone-IA, and Glacier Instant Retrieval have a 128 KB billable-size floor. Flexible Retrieval and Deep Archive add forty KB of metadata per object, split between Standard and archive rates.
Match lifecycle rules to the workload
An object’s age is not its time since last access. A thirty-day transition can affect a year-old report still read weekly. Evaluate object size, bytes retrieved, request frequency, retention, and acceptable restoration delay together. Prefixes and tags can distinguish workloads, but only if their classification stays accurate.
The September 2024 default prevents lifecycle transitions of objects smaller than 128 KB. Older unmodified configurations can retain the previous behavior, and explicit size filters can override defaults. Therefore, a small object remaining in Standard does not alone prove a broken rule. Inspect the configuration’s effective filters and history before attributing the outcome.
When it breaks
A lower storage subtotal can conceal higher retrieval and request charges. Conversely, a frequently read restored copy need not trigger a fresh archive restoration for every read while that copy remains available. Model the actual restore-and-read workflow, including temporary-copy storage, instead of multiplying archive restore charges by every GET.
A restore duration is also an operational dependency. Flexible Retrieval standard requests typically take three to five hours; Deep Archive standard requests typically finish within twelve hours, with bulk typically within forty-eight. These are documented expectations, not an unconditional deadline guarantee. Exercise restoration and verify completion before promising that a recovery-time objective is met.
Check it quickly
Run this standalone Python 3 script with assertions enabled. The earlier article reports Python 3.12.14 execution; no matching raw run record was recovered here, and this review did not rerun it. Its deliberately invented prices demonstrate sensitivity, not a current AWS quote or a complete bill. It compares one GiB retained for twelve modeled months and assumes every read retrieves the entire object.
from decimal import Decimal as D
# Invented rates, not an AWS quote; one GiB held for twelve modeled months.
warm_storage = D("0.02")
cold_storage = D("0.01")
retrieval_per_gib = D("0.01")
transition_per_object = D("0.001")
def annual_cost(full_reads):
warm = 12 * warm_storage
cold = 12 * cold_storage + full_reads * retrieval_per_gib + transition_per_object
return warm, cold
assert annual_cost(0) == (D("0.24"), D("0.121"))
assert annual_cost(52) == (D("0.24"), D("0.641"))
assert annual_cost(11)[1] < annual_cost(11)[0]
assert annual_cost(12)[1] > annual_cost(12)[0]
small_bytes, minimum_bytes = 10 * 1024, 128 * 1024
assert D(max(small_bytes, minimum_bytes)) / small_bytes == D("12.8")
assert max(10, 180) == 180 # Illustrative minimum-duration billing boundary.
for reads in (0, 11, 12, 52):
print(reads, "full reads:", tuple(map(str, annual_cost(reads))))
print("10 KiB under a 128 KiB floor: 12.8x billable size")
print("Excluded: GET requests, transfer, restored copies, tax, and negotiated rates")
Zero reads favor the colder model at 0.121 versus 0.24; fifty-two full reads reverse the choice to 0.641 versus 0.24. With these inputs, eleven reads remain cheaper and twelve do not. The size calculation shows why small-object floors need explicit treatment. Neither result establishes a universal class-selection threshold.
For an authorized bucket, the following unchanged AWS CLI diagnostics require configured read access and replacement of B and K. They were not executed during this review:
aws s3api list-objects-v2 --bucket B --query 'Contents[].StorageClass' --output text | tr '\t' '\n' | sort | uniq -c
aws s3api get-bucket-lifecycle-configuration --bucket B --query 'Rules[].[ID,Status,Transitions[0].Days,Transitions[0].StorageClass]' --output table
aws s3api head-object --bucket B --key K --query 'StorageClass'
For a successful nonempty listing, the first command counts current objects by class, not bytes or noncurrent versions. Handle empty listings and CLI errors separately; pipeline success alone does not validate the AWS call. The second shows only each rule’s first transition, omitting filters and later or noncurrent transitions; inspect the full response before deciding. HeadObject omits StorageClass for Standard, so a null projection is not itself a failure. None of these observations measures access frequency or proves that a pending transition or restore completed. Combine inventory, complete policy, access evidence, and billing before changing lifecycle behavior.
Sources
- AWS S3 pricing, billing dimensions, restore copies, and free-tier distinctions, checked 2026-10-15.
- AWS storage class guide, access, resilience, minimum duration, and billable size, checked 2026-10-15.
- AWS lifecycle transitions, small-object defaults and existing configurations, checked 2026-10-15.
- AWS archive retrieval options, typical restore durations, checked 2026-10-15.
- AWS CLI HeadObject, Standard omits StorageClass, checked 2026-10-15.
- AWS CLI ListObjectsV2, listing scope and object fields, checked 2026-10-15.
- AWS CLI lifecycle configuration, filters and transition arrays, checked 2026-10-15.