AWS S3 Lifecycle Rules, Replication and Intelligent Tiering

Published: June 6, 2026 • 15 min read

Amazon S3 is far more than a simple object store. It ships with a rich set of data-management primitives — lifecycle automation, multi-region replication, access-pattern-aware tiering, immutability controls, and versioning — that together let you cut storage costs by 70–90% while simultaneously improving durability and compliance posture. This guide walks through every one of those features with production-ready CLI commands and JSON policies you can paste straight into your pipelines.

1. S3 Storage Classes — Choosing the Right Tier

AWS offers eight storage classes, each tuned for a different access frequency and cost profile. Picking the wrong class for your data is one of the most common causes of unexpectedly high S3 bills.

Storage Class Use Case Availability SLA Min Storage Duration Retrieval Cost Approx. Price (per GB/mo)
S3 Standard Frequently accessed data 99.99% None Free $0.023
S3 Intelligent-Tiering Unknown or changing access 99.9% None Free (monitoring fee applies) $0.023 (frequent) / $0.0125 (infrequent)
S3 Standard-IA Infrequently accessed, rapid retrieval 99.9% 30 days $0.01/GB $0.0125
S3 One Zone-IA Infrequent access, reproducible data 99.5% 30 days $0.01/GB $0.01
S3 Glacier Instant Retrieval Archive, ms retrieval 99.9% 90 days $0.03/GB $0.004
S3 Glacier Flexible Retrieval Archive, 1–12 hr retrieval 99.99% 90 days $0.01/GB (standard) $0.0036
S3 Glacier Deep Archive Long-term archive, 12–48 hr retrieval 99.99% 180 days $0.02/GB $0.00099
S3 Express One Zone Single-AZ, sub-10ms latency 99.95% None Free $0.16
Key insight: Minimum storage duration fees mean that deleting a Glacier Instant object after 30 days still charges you for 90 days. Always factor this in when writing lifecycle expiration rules.

The general ladder is: Standard → Standard-IA → Glacier Instant → Glacier Flexible → Glacier Deep Archive. Lifecycle rules automate the descent; Intelligent-Tiering handles it automatically when access patterns are unpredictable.

2. S3 Lifecycle Rules

Lifecycle rules are bucket-level policies that tell S3 to automatically transition objects to cheaper storage classes or delete them after a set number of days. They are free to configure and run server-side with no compute cost to you.

2.1 Transition Actions

A transition action moves objects to a different storage class after a specified number of days since object creation (or since they became non-current for versioned buckets).

2.2 Expiration Actions

Expiration actions permanently delete objects (or non-current versions) after a threshold is reached. For versioned buckets, expiration adds a delete marker rather than immediately removing data; an additional NoncurrentVersionExpiration rule cleans up old versions.

2.3 Creating a Lifecycle Policy via AWS CLI

The following JSON policy implements a common cost-optimization ladder: move to Standard-IA after 30 days, Glacier Instant after 90 days, Glacier Deep Archive after 365 days, then delete after 2555 days (7 years). Non-current versions are pruned after 90 days.

# lifecycle-policy.json
{
  "Rules": [
    {
      "ID": "CostOptimizationLadder",
      "Status": "Enabled",
      "Filter": {
        "Prefix": "data/"
      },
      "Transitions": [
        {
          "Days": 30,
          "StorageClass": "STANDARD_IA"
        },
        {
          "Days": 90,
          "StorageClass": "GLACIER_IR"
        },
        {
          "Days": 365,
          "StorageClass": "DEEP_ARCHIVE"
        }
      ],
      "Expiration": {
        "Days": 2555
      },
      "NoncurrentVersionTransitions": [
        {
          "NoncurrentDays": 30,
          "StorageClass": "STANDARD_IA"
        },
        {
          "NoncurrentDays": 60,
          "StorageClass": "GLACIER_IR"
        }
      ],
      "NoncurrentVersionExpiration": {
        "NoncurrentDays": 90,
        "NewerNoncurrentVersions": 3
      },
      "AbortIncompleteMultipartUpload": {
        "DaysAfterInitiation": 7
      }
    }
  ]
}

Apply the policy with:

# Apply lifecycle policy to a bucket
aws s3api put-bucket-lifecycle-configuration \
  --bucket my-production-bucket \
  --lifecycle-configuration file://lifecycle-policy.json

# Verify the policy was applied
aws s3api get-bucket-lifecycle-configuration \
  --bucket my-production-bucket
Note: The NewerNoncurrentVersions field (added in 2023) lets you keep the N most recent non-current versions regardless of age. Use it to ensure you always have rollback points while still deleting very old versions.

2.4 Lifecycle Rule Filters

Filters can target objects by prefix, tag, or object size range. You can combine a prefix with tags using And:

"Filter": {
  "And": {
    "Prefix": "logs/",
    "Tags": [
      { "Key": "Environment", "Value": "production" }
    ],
    "ObjectSizeGreaterThan": 131072
  }
}

This targets only objects under logs/ tagged as production that are larger than 128 KB — preventing small objects (which have per-object overhead that makes IA tiers uneconomical) from being transitioned prematurely.

3. S3 Versioning

Versioning preserves every overwrite and delete of an object. Once enabled on a bucket it cannot be fully disabled — only suspended (existing versions are retained). Versioning is a prerequisite for replication and Object Lock.

3.1 Enable Versioning

# Enable versioning
aws s3api put-bucket-versioning \
  --bucket my-production-bucket \
  --versioning-configuration Status=Enabled

# Check versioning status
aws s3api get-bucket-versioning \
  --bucket my-production-bucket

# List all versions of objects in a bucket
aws s3api list-object-versions \
  --bucket my-production-bucket \
  --prefix data/reports/ \
  --query 'Versions[*].{Key:Key,VersionId:VersionId,LastModified:LastModified}'

3.2 MFA Delete

MFA Delete adds a second factor requirement before permanently deleting object versions or changing the versioning state. It can only be enabled by the bucket owner using root credentials:

# Enable MFA Delete (requires root credentials and MFA device serial + TOTP code)
aws s3api put-bucket-versioning \
  --bucket my-production-bucket \
  --versioning-configuration Status=Enabled,MFADelete=Enabled \
  --mfa "arn:aws:iam::123456789012:mfa/root-account-mfa-device 123456"
Best practice: Enable MFA Delete on buckets that hold compliance data or production backups. This prevents accidental or malicious bulk deletion even if long-term credentials are compromised.

3.3 Lifecycle Rules for Versioned Buckets

In versioned buckets use NoncurrentVersionTransition and NoncurrentVersionExpiration (covered in section 2.3) alongside the standard Transitions and Expiration rules. Also add an ExpiredObjectDeleteMarker rule to clean up stale delete markers that accumulate when all versions of an object have been deleted:

{
  "Rules": [
    {
      "ID": "CleanDeleteMarkers",
      "Status": "Enabled",
      "Filter": {},
      "Expiration": {
        "ExpiredObjectDeleteMarker": true
      }
    }
  ]
}

4. S3 Intelligent-Tiering

S3 Intelligent-Tiering is a storage class that automatically moves objects between access tiers based on real usage patterns. Unlike manual lifecycle rules, it requires zero configuration of transition thresholds.

4.1 How It Works

  • Frequent Access tier: Default for newly uploaded objects. Cost identical to S3 Standard ($0.023/GB).
  • Infrequent Access tier: Objects not accessed for 30 consecutive days are moved here. Cost $0.0125/GB.
  • Archive Instant Access tier: Objects not accessed for 90 days. Cost $0.004/GB. Retrieval in milliseconds.
  • Archive Access tier (opt-in): Configurable 90–730 days. Cost $0.0036/GB. Retrieval 3–5 hours.
  • Deep Archive Access tier (opt-in): Configurable 180–730 days. Cost $0.00099/GB. Retrieval 12 hours.

4.2 Monitoring Fee

Intelligent-Tiering charges a per-object monitoring fee of $0.0025 per 1,000 objects per month. This makes it uneconomical for objects smaller than 128 KB — the monitoring cost outweighs any storage savings. Use lifecycle rules with an ObjectSizeGreaterThan filter to move only larger objects into Intelligent-Tiering.

4.3 Enabling Intelligent-Tiering on a Bucket

# Upload an object directly into Intelligent-Tiering
aws s3 cp large-dataset.parquet s3://my-production-bucket/data/ \
  --storage-class INTELLIGENT_TIERING

# Configure bucket-level Intelligent-Tiering with archive tiers enabled
aws s3api put-bucket-intelligent-tiering-configuration \
  --bucket my-production-bucket \
  --id FullArchiveConfig \
  --intelligent-tiering-configuration '{
    "Id": "FullArchiveConfig",
    "Status": "Enabled",
    "Filter": {
      "Prefix": "analytics/"
    },
    "Tierings": [
      {
        "Days": 90,
        "AccessTier": "ARCHIVE_ACCESS"
      },
      {
        "Days": 180,
        "AccessTier": "DEEP_ARCHIVE_ACCESS"
      }
    ]
  }'

# Verify the configuration
aws s3api get-bucket-intelligent-tiering-configuration \
  --bucket my-production-bucket \
  --id FullArchiveConfig

4.4 When to Use Intelligent-Tiering

Intelligent-Tiering is the right choice when:

  • Access patterns are unknown or change over time (e.g., data lake with ad-hoc queries)
  • Objects are larger than 128 KB
  • You cannot tolerate the operational overhead of manually tuning lifecycle thresholds
  • You want millisecond retrieval even for archived objects (Archive Instant Access)
Cost tip: Combine lifecycle rules with Intelligent-Tiering: use a lifecycle rule to transition objects to INTELLIGENT_TIERING after 1 day, filtered to objects > 128 KB. Small objects and short-lived temp files can be expired separately.

5. Cross-Region Replication (CRR)

CRR automatically copies objects from a source bucket in one AWS region to a destination bucket in a different region. It provides geographic redundancy, low-latency reads for globally distributed applications, and compliance with data residency requirements.

5.1 Prerequisites

  • Versioning must be enabled on both source and destination buckets
  • An IAM role granting S3 permission to replicate on your behalf
  • Source and destination buckets must be owned by the same account (for same-account CRR) or the destination bucket policy must grant access (for cross-account CRR)

5.2 IAM Role for Replication

# s3-replication-trust-policy.json — trust policy for the IAM role
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "s3.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

# s3-replication-permissions.json — permissions policy attached to the role
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetReplicationConfiguration",
        "s3:ListBucket"
      ],
      "Resource": "arn:aws:s3:::source-bucket"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObjectVersionForReplication",
        "s3:GetObjectVersionAcl",
        "s3:GetObjectVersionTagging"
      ],
      "Resource": "arn:aws:s3:::source-bucket/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:ReplicateObject",
        "s3:ReplicateDelete",
        "s3:ReplicateTags"
      ],
      "Resource": "arn:aws:s3:::destination-bucket/*"
    }
  ]
}
# Create the IAM role
aws iam create-role \
  --role-name S3ReplicationRole \
  --assume-role-policy-document file://s3-replication-trust-policy.json

# Attach the permissions policy
aws iam put-role-policy \
  --role-name S3ReplicationRole \
  --policy-name S3ReplicationPermissions \
  --policy-document file://s3-replication-permissions.json

5.3 Replication Configuration JSON

# replication-config.json
{
  "Role": "arn:aws:iam::123456789012:role/S3ReplicationRole",
  "Rules": [
    {
      "ID": "ReplicateAllToDR",
      "Status": "Enabled",
      "Filter": {
        "Prefix": ""
      },
      "Destination": {
        "Bucket": "arn:aws:s3:::destination-bucket-us-west-2",
        "StorageClass": "STANDARD_IA",
        "ReplicationTime": {
          "Status": "Enabled",
          "Time": {
            "Minutes": 15
          }
        },
        "Metrics": {
          "Status": "Enabled",
          "EventThreshold": {
            "Minutes": 15
          }
        }
      },
      "DeleteMarkerReplication": {
        "Status": "Enabled"
      },
      "SourceSelectionCriteria": {
        "SseKmsEncryptedObjects": {
          "Status": "Enabled"
        }
      }
    }
  ]
}

# Apply the replication configuration
aws s3api put-bucket-replication \
  --bucket source-bucket \
  --replication-configuration file://replication-config.json

# Verify replication status of a specific object
aws s3api head-object \
  --bucket source-bucket \
  --key data/important-file.parquet \
  --query 'ReplicationStatus'

5.4 S3 Replication Time Control (RTC)

Standard replication has no SLA — objects are replicated within minutes but AWS does not guarantee a maximum time. S3 Replication Time Control (RTC) provides an SLA of 99.99% of objects replicated within 15 minutes. RTC is enabled in the replication config as shown above (ReplicationTime with Minutes: 15). It costs an additional $0.015 per GB replicated and an additional $0.01 per million objects.

Note: RTC requires S3 Metrics to be enabled on the destination (the Metrics block in the config above). CloudWatch metrics then expose ReplicationLatency and BytesPendingReplication for monitoring.

6. Same-Region Replication (SRR)

SRR uses the same configuration mechanism as CRR but both buckets live in the same AWS region. The setup is identical — versioning on both buckets, an IAM replication role, and a replication configuration JSON.

6.1 SRR Use Cases

  • Log aggregation: Multiple application buckets replicate into a single central logging bucket in the same region for unified analysis.
  • Compliance copy: Regulated data must be kept in a separate bucket owned by a compliance team that auditors can access independently.
  • Test/staging environments: Replicate production data into a staging bucket in the same region with different permissions, without the cost of cross-region data transfer.
  • Account separation: SRR works cross-account within the same region — useful for isolating production and DR accounts while keeping data local.

SRR replication does not incur data transfer costs because data stays within the same region. You only pay for the S3 PUT requests at the destination.

# SRR — enable versioning on both buckets in us-east-1
aws s3api put-bucket-versioning \
  --bucket source-logs-bucket \
  --versioning-configuration Status=Enabled

aws s3api put-bucket-versioning \
  --bucket central-logs-bucket \
  --versioning-configuration Status=Enabled

# Apply replication config (same JSON structure as CRR, just same-region ARNs)
aws s3api put-bucket-replication \
  --bucket source-logs-bucket \
  --replication-configuration file://srr-config.json

7. S3 Object Lock

S3 Object Lock implements Write Once Read Many (WORM) storage. Once enabled on a bucket, objects can be protected from deletion or overwrite for a fixed retention period — or indefinitely. Object Lock is essential for SEC 17a-4(f), CFTC, FINRA, and HIPAA compliance workloads.

Warning: Object Lock must be enabled at bucket creation time. It cannot be enabled on an existing bucket. Enabling it also automatically enables versioning and that cannot be suspended.

7.1 Retention Modes

Governance Mode — Users with the s3:BypassGovernanceRetention IAM permission can delete or overwrite locked objects. Useful for internal compliance where you need an escape hatch for administrators.

Compliance Mode — No user, including the root account, can delete or overwrite a locked object before its retention period expires. The retention period itself cannot be shortened. Use this for regulatory mandates that require tamper-proof evidence.

7.2 Legal Hold

A legal hold is an on/off flag independent of the retention period. It prevents deletion regardless of any configured retention. Legal holds are used during litigation to preserve relevant objects indefinitely, then removed once the case is resolved.

7.3 Configuring Object Lock

# Create a new bucket with Object Lock enabled
aws s3api create-bucket \
  --bucket compliance-archive-bucket \
  --region us-east-1 \
  --object-lock-enabled-for-bucket

# Set a default retention policy on the bucket (applied to all new objects)
aws s3api put-object-lock-configuration \
  --bucket compliance-archive-bucket \
  --object-lock-configuration '{
    "ObjectLockEnabled": "Enabled",
    "Rule": {
      "DefaultRetention": {
        "Mode": "COMPLIANCE",
        "Years": 7
      }
    }
  }'

# Apply a retention override on a specific object version
aws s3api put-object-retention \
  --bucket compliance-archive-bucket \
  --key financial-records/2026-q1.csv \
  --version-id abc123XYZ \
  --retention '{
    "Mode": "COMPLIANCE",
    "RetainUntilDate": "2033-01-01T00:00:00Z"
  }'

# Place a legal hold on an object
aws s3api put-object-legal-hold \
  --bucket compliance-archive-bucket \
  --key financial-records/2026-q1.csv \
  --version-id abc123XYZ \
  --legal-hold Status=ON

# Remove legal hold once litigation is resolved
aws s3api put-object-legal-hold \
  --bucket compliance-archive-bucket \
  --key financial-records/2026-q1.csv \
  --version-id abc123XYZ \
  --legal-hold Status=OFF
Use Governance mode for development and staging, Compliance mode for production regulatory data. In Governance mode you can test your lock configuration and correct mistakes; switching to Compliance mode hardens the policy for production.

8. Cost Optimization Patterns

The previous sections covered individual features. Here is how to combine them into a coherent cost-optimization strategy for a real-world production bucket.

8.1 Tiered Lifecycle + Intelligent-Tiering Hybrid

For workloads where some data is accessed frequently and some is accessed unpredictably:

  1. Use standard S3 Standard for the first 24–48 hours (new data is always accessed during ingestion pipelines).
  2. Transition to INTELLIGENT_TIERING after 1 day for objects > 128 KB. Intelligent-Tiering handles the rest automatically.
  3. Use a separate lifecycle rule to delete temp/staging objects (prefix tmp/) after 7 days.
  4. Use NoncurrentVersionExpiration with NewerNoncurrentVersions: 3 to keep only the 3 most recent versions.

8.2 Delete Incomplete Multipart Uploads

Incomplete multipart uploads accumulate silently and incur storage charges even though no complete object exists. The AbortIncompleteMultipartUpload lifecycle rule (shown in section 2.3) is the fix. This alone has saved companies thousands of dollars on large data pipeline buckets.

# Find incomplete multipart uploads in a bucket
aws s3api list-multipart-uploads \
  --bucket my-production-bucket \
  --query 'Uploads[*].{Key:Key,Initiated:Initiated,UploadId:UploadId}'

# Manually abort a specific incomplete upload
aws s3api abort-multipart-upload \
  --bucket my-production-bucket \
  --key large-file.tar.gz \
  --upload-id "VXBsb2FkIElEIGZvciA2aWWpbmcncyBteS1tb3ZpZS5tMnRzIHVwbG9hZA"

8.3 S3 Inventory for Cost Analysis

Before tuning lifecycle rules, run S3 Inventory to understand your actual data distribution. Inventory produces daily or weekly CSV/ORC/Parquet reports with object size, storage class, last accessed date, replication status, and encryption status — perfect for feeding into Athena or a notebook for analysis.

# Enable S3 Inventory on a bucket (daily CSV report to a destination bucket)
aws s3api put-bucket-inventory-configuration \
  --bucket my-production-bucket \
  --id DailyCostInventory \
  --inventory-configuration '{
    "Id": "DailyCostInventory",
    "IsEnabled": true,
    "Destination": {
      "S3BucketDestination": {
        "Bucket": "arn:aws:s3:::my-inventory-reports-bucket",
        "Format": "Parquet",
        "Prefix": "inventory/my-production-bucket"
      }
    },
    "Schedule": {
      "Frequency": "Daily"
    },
    "IncludedObjectVersions": "All",
    "OptionalFields": [
      "Size",
      "LastModifiedDate",
      "StorageClass",
      "ETag",
      "ReplicationStatus",
      "EncryptionStatus",
      "IntelligentTieringAccessTier"
    ]
  }'
Typical savings with full optimization: A 100 TB bucket of 90-day-old analytics data storing exclusively in S3 Standard costs ~$2,300/month. Moving it to a lifecycle-managed mix of Standard-IA → Glacier Deep Archive reduces that to ~$250/month — an 89% reduction.

8.4 Summary: Optimization Checklist

  • Enable lifecycle rules with AbortIncompleteMultipartUpload on every bucket
  • Add NoncurrentVersionExpiration with NewerNoncurrentVersions on all versioned buckets
  • Add ExpiredObjectDeleteMarker rule to remove stale delete markers
  • Filter lifecycle transitions with ObjectSizeGreaterThan: 131072 to avoid per-object IA overhead on small files
  • Use Intelligent-Tiering for datasets with unknown or changing access patterns
  • Enable S3 Inventory and schedule monthly Athena queries to identify optimization opportunities
  • Tag buckets and objects with Environment and CostCenter for granular Cost Explorer breakdown
  • Enable CRR with RTC only where a 15-minute RPO SLA is actually required — SRR for compliance copies is cheaper

Read Next