Definition
- S3 (Simple Storage Service) – a highly durable, virtually unlimited object storage service that stores files as objects inside buckets, accessed over HTTP APIs, with eleven nines (99.999999999%) of durability.
- Storage classes – tiers tuned to different access patterns: Standard for frequent access, Intelligent-Tiering for unknown patterns, Standard-IA and One Zone-IA for infrequent access, and Glacier classes for archival.
- Glacier tiers – Instant Retrieval (milliseconds), Flexible Retrieval (minutes to hours), and Deep Archive (up to twelve hours retrieval).
- Lifecycle policy – a set of rules on a bucket that automatically transitions objects to cheaper classes as they age and expires (deletes) them when retention is met.
- Cost model – you pay for storage, requests, retrieval (for IA/Glacier classes), and data transfer out.
Think of S3 as the giant document warehouse of National Bank of India where every statement PDF, scanned cheque, and KYC document is stored. The storage classes are different shelves. The front shelf (Standard) is for this month's statements that customers open often – fast but expensive. A middle shelf (Standard-IA) is for last year's documents opened occasionally. A deep basement vault (Glacier Deep Archive) is for ten-year-old records the bank must legally keep but almost never opens – very cheap but slow to fetch. A lifecycle policy is the warehouse rule that says "after 30 days move a statement from the front shelf to the middle shelf, after one year to the basement, and after ten years shred it," done automatically.
Understanding the Concepts
What is S3?
S3 stores objects, not blocks or files on a disk. Each object has a key (its name), data, and metadata, and lives in a bucket with a globally unique name. S3 gives eleven nines of durability by replicating objects across multiple devices and, for most classes, multiple Availability Zones. You access it with simple API calls: PutObject, GetObject, DeleteObject.
package com.bank.storage;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*;
import java.nio.file.Path;
public class StatementUploader {
private final S3Client s3 = S3Client.builder().build();
public void uploadStatement(String accountId, Path filePath) {
s3.putObject(
PutObjectRequest.builder()
.bucket("nbi-statements")
.key("2026/10/" + accountId + "-statement.pdf")
.storageClass(StorageClass.STANDARD)
.build(),
filePath);
System.out.println("Statement uploaded for account: " + accountId);
}
}
Why do we need different storage classes?
Not all data is accessed equally. A statement generated today is read many times this month, occasionally next year, and almost never after that, but banking regulations may require keeping it for ten years. Paying Standard storage rates for data nobody reads is wasteful. Storage classes let you trade retrieval speed against storage cost based on how often data is actually accessed.
// Cost comparison model for storage class selection
package com.bank.storage;
import java.math.BigDecimal;
public class StorageCostEstimator {
// Approximate per-GB-month costs (illustrative)
private static final BigDecimal STANDARD_PER_GB = new BigDecimal("0.023");
private static final BigDecimal STANDARD_IA_PER_GB = new BigDecimal("0.0125");
private static final BigDecimal GLACIER_FA_PER_GB = new BigDecimal("0.0036");
private static final BigDecimal DEEP_ARCHIVE_PER_GB = new BigDecimal("0.00099");
public static BigDecimal monthlyCost(String storageClass, long sizeGB) {
BigDecimal rate = switch (storageClass) {
case "STANDARD" -> STANDARD_PER_GB;
case "STANDARD_IA" -> STANDARD_IA_PER_GB;
case "GLACIER" -> GLACIER_FA_PER_GB;
case "DEEP_ARCHIVE" -> DEEP_ARCHIVE_PER_GB;
default -> throw new IllegalArgumentException("Unknown class: " + storageClass);
};
return rate.multiply(BigDecimal.valueOf(sizeGB));
}
}
How does each storage class work?
S3 Standard stores data across at least three Availability Zones with low latency and high throughput. It is the default for frequently accessed data.
S3 Intelligent-Tiering monitors each object and automatically moves it between a frequent-access tier, an infrequent-access tier, and optional archive tiers based on actual usage. It charges a small monitoring fee per object but saves you from guessing access patterns.
S3 Standard-IA is cheaper to store but charges a per-gigabyte retrieval fee, suited for data accessed a few times a year. It still uses three Availability Zones.
S3 One Zone-IA is like Standard-IA but stored in a single Availability Zone, so it is cheaper but the data is lost if that zone is destroyed. Use it only for reproducible data.
S3 Glacier Instant Retrieval stores rarely accessed data but still gives millisecond retrieval, good for compliance records that must be instantly available when needed.
S3 Glacier Flexible Retrieval is cheaper and retrieves in minutes (expedited), hours (standard), or five to twelve hours (bulk).
S3 Glacier Deep Archive is the cheapest of all, for data retained seven to ten years for regulation, retrieved in up to twelve hours.
// Selecting the right storage class based on access frequency
package com.bank.storage;
public class StorageClassSelector {
public static String select(int accessesPerYear, boolean reproducible, int retentionYears) {
if (retentionYears > 5 && accessesPerYear == 0) return "DEEP_ARCHIVE";
if (retentionYears > 1 && accessesPerYear < 2) return "GLACIER_FR";
if (accessesPerYear < 12 && reproducible) return "ONEZONE_IA";
if (accessesPerYear < 12) return "STANDARD_IA";
return "STANDARD";
}
}
How do lifecycle policies work?
A lifecycle policy is a set of rules on a bucket that automate transitions and expirations. You can scope rules to a prefix or tag and specify the number of days after object creation for each transition. Rules can also clean up incomplete multipart uploads and expire noncurrent versions in versioned buckets.
// Creating a lifecycle policy with the AWS SDK
package com.bank.storage;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*;
import java.util.List;
public class LifecyclePolicyCreator {
private final S3Client s3 = S3Client.create();
public void applyStatementLifecycle() {
LifecycleRule rule = LifecycleRule.builder()
.id("statement-tiering")
.filter(LifecycleRuleFilter.builder().prefix("statements/").build())
.status(ExpirationStatus.ENABLED)
.transitions(List.of(
Transition.builder().days(30).storageClass(TransitionStorageClass.STANDARD_IA).build(),
Transition.builder().days(90).storageClass(TransitionStorageClass.GLACIER).build(),
Transition.builder().days(365).storageClass(TransitionStorageClass.DEEP_ARCHIVE).build()))
.expiration(LifecycleExpiration.builder().days(3650).build()) // 10 years
.build();
s3.putBucketLifecycleConfiguration(
PutBucketLifecycleConfigurationRequest.builder()
.bucket("nbi-statements")
.lifecycleConfiguration(BucketLifecycleConfiguration.builder()
.rules(rule).build())
.build());
}
}
What are the rules and constraints of transitions?
Transitions have minimums and small per-object charges. Standard-IA has a minimum storage duration of 30 days. Glacier classes have a minimum of 90 days for Flexible Retrieval and 180 days for Deep Archive. Transitioning millions of tiny objects too early can cost more than it saves, because each transition incurs a per-request charge. Objects smaller than 128 KB are not transitioned to IA or Glacier classes.
// Validating transition eligibility
package com.bank.storage;
public class TransitionValidator {
private static final long MIN_OBJECT_SIZE_BYTES = 128 * 1024; // 128 KB
private static final int MIN_DAYS_FOR_IA = 30;
public static boolean canTransitionToIA(long objectSizeBytes, int ageDays) {
if (objectSizeBytes < MIN_OBJECT_SIZE_BYTES) {
System.out.println("Object too small for IA transition");
return false;
}
if (ageDays < MIN_DAYS_FOR_IA) {
System.out.println("Object not old enough for IA transition");
return false;
}
return true;
}
}
How is Intelligent-Tiering different from manual lifecycle rules?
Intelligent-Tiering reacts to real usage, monitoring each object individually and moving it to cheaper tiers when not accessed and back to the frequent tier when accessed again. Manual lifecycle rules are time-based: they transition by age, regardless of whether the object is still being accessed. For unpredictable access patterns, Intelligent-Tiering is safer because it does not accidentally move hot data to a cold tier.
// Choosing between Intelligent-Tiering and manual lifecycle
package com.bank.storage;
public class TieringStrategy {
public static String recommend(boolean accessPatternKnown, int objectCount) {
if (!accessPatternKnown) {
return "INTELLIGENT_TIERING"; // reacts to actual usage
}
if (objectCount > 1_000_000) {
return "LIFECYCLE_RULES"; // predictable pattern, avoid monitoring fee
}
return "INTELLIGENT_TIERING"; // safe default
}
}
What are common mistakes with S3 storage classes?
The most common mistake is never setting a lifecycle policy, so data sits in Standard forever even when nobody reads it. A second mistake is transitioning too aggressively: moving objects to Glacier after one day when they might still be accessed, triggering retrieval fees that exceed the storage savings. A third mistake is using One Zone-IA for critical data that is not reproducible.
// Wrong: no lifecycle policy, paying Standard rates for 10-year-old data
// The bucket has 50 TB of old statements all in Standard
// Monthly cost: 50000 * $0.023 = $1150
// Correct: lifecycle policy moves old data to cheaper tiers
// 30d -> Standard-IA, 90d -> Glacier, 365d -> Deep Archive
// Most of the 50 TB is now in Deep Archive
// Monthly cost: 50000 * $0.00099 = $49.50 (97% savings)
What should a senior engineer know?
Senior engineers understand that S3 request pricing matters as much as storage pricing at scale. Millions of small GET or PUT requests add up quickly. They also know that S3 Transfer Acceleration uses CloudFront edge locations to speed uploads over long distances, that Cross-Region Replication can replicate objects to another Region for disaster recovery, and that S3 Object Lock provides write-once-read-many (WORM) compliance for regulatory retention. The interplay between lifecycle rules and versioning is critical: you must explicitly target noncurrent versions in your lifecycle rules, or old versions accumulate silently.
// Enabling Cross-Region Replication for disaster recovery
package com.bank.storage;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*;
public class ReplicationSetup {
public void enableCrossRegionReplication(String sourceBucket, String destBucket) {
// Requires versioning enabled on both buckets
// and an IAM role with s3:ReplicateObject permissions
System.out.println("CRR: " + sourceBucket + " -> " + destBucket);
System.out.println("All new objects replicated to DR region automatically");
}
}
Visual Overview
S3 Storage Classes – Cost vs Speed
Retrieval Speed Storage Cost
(fast) (high)
│ │
│ ┌──────────────┐ │
│ │ S3 Standard │ │ Frequently accessed
│ └──────┬───────┘ │
│ │ │
│ ┌──────┴───────┐ │
│ │ Intelligent- │ │ Unknown access pattern
│ │ Tiering │ │ (auto-moves between tiers)
│ └──────┬───────┘ │
│ │ │
│ ┌──────┴───────┐ │
│ │ Standard-IA │ │ Few times per year
│ │ One Zone-IA │ │ (retrieval fee applies)
│ └──────┬───────┘ │
│ │ │
│ ┌──────┴───────┐ │
│ │Glacier Instant│ │ Rarely, but ms retrieval
│ └──────┬───────┘ │
│ │ │
│ ┌──────┴───────┐ │
│ │Glacier Flex │ │ Minutes to hours
│ └──────┬───────┘ │
│ │ │
│ ┌──────┴───────┐ │
│ │ Deep Archive │ │ Up to 12 hours
▼ └──────────────┘ ▼
(slow) (low)
Lifecycle Policy Flow (Statement PDFs)
┌──────────┐ 30d ┌──────────┐ 90d ┌──────────┐ 365d ┌──────────┐
│ Standard │──────→│Stand-IA │──────→│ Glacier │──────→│Deep Arch │
└──────────┘ └──────────┘ └──────────┘ └────┬─────┘
│ 3650d
▼
┌──────────┐
│ EXPIRED │
│(deleted) │
└──────────┘
Key Takeaway
Amazon S3 is highly durable object storage that keeps files as objects inside buckets, accessed over HTTP APIs, and gives eleven nines of durability by replicating data across multiple devices and Availability Zones. Unlike a disk, it is effectively unlimited, and you pay for what you store and retrieve.
The storage classes let you trade retrieval speed against cost based on how often data is accessed. S3 Standard is for frequently accessed data with low latency. Intelligent-Tiering automatically moves each object between frequent and infrequent tiers based on real usage, which is ideal when the access pattern is unknown. Standard-IA and One Zone-IA are cheaper for infrequently accessed data, with One Zone-IA trading durability for a lower price by living in a single Availability Zone. The Glacier classes are archival: Instant Retrieval returns in milliseconds, Flexible Retrieval in minutes to hours, and Deep Archive is the cheapest at up to twelve hours for long-term compliance data.
Lifecycle policies are what make this automatic and affordable. I attach rules to a bucket that transition objects to colder classes as they age and finally expire them when retention is met, and the rules can also clean up old versions and incomplete multipart uploads. The nuance I always raise is that transitions carry small per-object charges and minimum durations, so transitioning millions of tiny objects too aggressively can cost more than it saves, and for unpredictable access patterns Intelligent-Tiering is safer than a fixed-age rule because it reacts to actual usage.
At National Bank of India we generated millions of statement PDFs that are opened heavily in the first month, rarely after that, yet must be retained for ten years by regulation. I wrote a lifecycle policy that keeps new statements in Standard, moves them to Standard-IA after thirty days, to Glacier Flexible Retrieval after ninety days, to Deep Archive after a year, and expires them at ten years. That single policy cut our storage bill by over ninety percent while meeting the retention rule, and because it runs automatically no one ever has to move a file by hand.
Remember one sentence: S3 storage classes trade retrieval speed for cost, and lifecycle policies automate the transitions as data ages, so you pay the cheapest rate for each object based on how often it is actually accessed.
---