# S3 Storage Tier Migration

> STANDARD-dominant S3 buckets with no lifecycle policy and a measured access rate under 1,000 requests per day hold cold data at the most expensive tier. ZopNight fires on the aggregator's per-bucket STANDARD-to- STANDARD_IA delta, which is (standard rate minus IA rate) times GB times 730 hours clamped to cost. Hot or unmeasured buckets abstain.

Source: https://zop.dev/integrations/aws/recommendations/s3-storage-tier-migration
Updated: 2026-08-19

---

## Which STANDARD buckets qualify as cold

- resource.InstanceType == STANDARD (discoverer sets InstanceType to the largest-by-bytes dominant storage class, and only STANDARD buckets are retier candidates)
- Metadata["lifecycle_policy_present"]: skip when a policy already manages transitions
- PricingAware: per-resource monthly cost (applicability gate)
- metric: S3AccessRatePerDay, the required cold-data gate; abstains when the series is absent ([S3 request metrics](https://docs.aws.amazon.com/AmazonS3/latest/userguide/metrics-dimensions.html) not enabled) or avg ≥ 1000 req/day (hot bucket; IA retrieval/request fees would erase the saving)
- injected per-bucket STANDARD→STANDARD_IA retier delta (SetS3StandardToIASavings, a dedicated S3 field, deliberately not the Azure RetierSavings map, so the two never double-count). Wired: aggregator calcS3 (cost/calc_aws_storage.go, s3RetierDeltas) sets CostOutput.S3StandardToIASavingsUSD; abstains when absent or non-positive.

## Pricing the STANDARD to Standard-IA delta

concrete-or-abstain (cost-driven rightsizing). savings = ([stdRate − iaRate](https://aws.amazon.com/s3/pricing/)) × stdGB × hoursPerMonth, the aggregator's per-bucket STANDARD→STANDARD_IA retier delta, injected via SetS3StandardToIASavings (clamped to cost). The former path emitted SavingsUSD=0 under Category="advisory" (a $0 advisory cost rec, forbidden); the prior cost*0.30 fraction is also removed. The producer chain (calcS3 CostOutput.S3StandardToIASavingsUSD → ComputedCostEntry → s3IADeltaMap → SetS3StandardToIASavings, recommender service.go) is wired end-to-end, so the rule fires concretely on a STANDARD-dominant, no-lifecycle, measured-cold bucket with a positive delta and abstains otherwise, never emitting a fraction-of-bill or $0 phantom.

## Moving data to a cheaper tier

1. Review S3 Storage Lens to analyze access patterns
2. Enable S3 Intelligent-Tiering for automatic tier management
3. For known-cold data: add lifecycle rules to transition to Standard-IA after 30 days
4. For archives: choose the appropriate Glacier tier (Instant Retrieval / Flexible Retrieval / Deep Archive)

## The access-rate series that gates it

S3AccessRatePerDay (aggregator metrics/aws/s3_access.go; MultiMetricsAware cold-bucket gate)
