AWS S3 Lifecycle Policies Explained: Rules, Examples & Costs
An S3 lifecycle policy is a set of rules that tell S3 what to do with objects as they age: move them to a cheaper storage class, or delete them entirely. You configure it once and S3 handles the rest, so you stop paying Standard prices for data that no one has accessed in months.
Simple explanation
Imagine a physical filing office with three rooms. When a document arrives it goes in the active room at the front desk: easy to grab, but expensive floor space. After 30 days it moves to a back-room filing cabinet: still accessible, but you have to walk to get it. After 90 days it goes into off-site archive storage. After a year it gets shredded.
S3 lifecycle policies work the same way. You write a rule that says: after 30 days, move this object to Standard-IA; after 90 days, move it to Glacier; after 365 days, delete it. S3 checks object ages daily and moves things along the chain automatically.
You do not need a cron job, a Lambda function, or any external process. A lifecycle policy is a JSON document attached to the S3 bucket, and S3 runs the actions for you as objects age.
How it works
Lifecycle rules operate on a simple age-based trigger:
- Object lands in the bucket. S3 records its creation date.
- Rule matching. Each lifecycle rule has a filter: a prefix, a tag, or no filter at all. S3 checks whether the object key and tags match the rule.
- Age threshold reached. Once the object is old enough (measured in days since creation, or days since it became a noncurrent version), the rule becomes eligible to fire.
- S3 performs the action asynchronously. Transitions and expirations are not instant. AWS runs lifecycle processing in the background, typically within 24 hours of the configured day. An object with a 30-day transition rule will not move at midnight on day 30 exactly. It may take until day 31 depending on when the job runs.
Rules never fire early. An object will not be transitioned or deleted before the configured day count is reached.
You can have multiple rules on the same bucket, and they run independently. One rule can transition logs/ objects while another expires temp-exports/ objects. They do not interfere with each other unless their filters overlap.
When to use this
Lifecycle policies work best when object access patterns are predictable and time-based. Common situations:
- Application logs. Logs from the last week are queried actively. Logs from last month are checked during incident reviews. Logs older than 90 days are kept for compliance but rarely opened. A three-stage lifecycle rule covers this exactly and significantly cuts the cost of long-term log retention.
- Database or VM backups. Daily backups older than 30 days rarely need to be retrieved quickly. Moving them to Standard-IA or Glacier after a set period keeps them available without paying Standard pricing for cold data.
- Exported reports. A finance team generates monthly CSVs that are reviewed for 30 days and then archived. A lifecycle rule can automatically move these to a cold tier once that window closes.
- Compliance archives. Some industries require objects to be retained for 7 years. Lifecycle rules can automate the transition to Glacier Deep Archive (the cheapest tier) after the active period ends, and trigger expiration at the end of the retention window.
- Versioned buckets with growing old versions. If S3 versioning is enabled and you never clean up noncurrent versions, storage costs accumulate silently. Lifecycle rules can automatically move old versions to cheaper classes and delete them after a defined period.
When not to use this
Lifecycle policies are not the right tool in every case.
Access patterns are unpredictable. If you cannot reliably predict when objects will go cold (for example, a media library where some assets are re-requested months later without warning), a lifecycle rule risks moving frequently-needed objects to a slow or expensive-to-retrieve tier. S3 Intelligent-Tiering is a better fit here, since it monitors access automatically and adjusts without a fixed schedule.
Data is accessed frequently. Objects that are read often should stay in Standard or Standard-IA. Transitioning frequently accessed objects to Glacier will slow your application down and generate unexpected retrieval costs.
Objects are small and short-lived. Lifecycle transitions have per-request overhead. If you have millions of tiny objects kept for only a few days, the overhead of managing transitions may not be worth the marginal cost saving. Minimum storage duration charges (covered below) can actually increase your bill.
Objects stored in Glacier Flexible Retrieval or Deep Archive must be restored before they can be accessed. Restoration to Glacier Flexible Retrieval takes 1–12 hours; Deep Archive takes 12–48 hours. If you need an object available on demand at any point in its lifetime, do not archive it to Glacier.
Lifecycle actions
There are six action types you can include in a lifecycle rule. A single rule can combine multiple types.
Transition#
Moves an object to a different S3 storage class after a set number of days. Common targets:
| StorageClass value (JSON/CLI) | What it is |
|---|---|
STANDARD_IA | S3 Standard-IA: lower storage cost, retrieval fee applies |
ONEZONE_IA | Single-AZ version of Standard-IA: cheaper, less resilient |
INTELLIGENT_TIERING | Automatic tiering based on access patterns |
GLACIER | S3 Glacier Flexible Retrieval: cheap archive, 1–12 hour retrieval |
DEEP_ARCHIVE | S3 Glacier Deep Archive: cheapest tier, 12–48 hour retrieval |
GLACIER is the API and CLI identifier for S3 Glacier Flexible Retrieval (formerly Amazon Glacier). It is not the same as Glacier Deep Archive, which uses DEEP_ARCHIVE. The AWS console may label these with different display names, but in JSON lifecycle configurations and CLI commands you must use the exact string values above.
Minimum storage duration charges apply. Standard-IA and One Zone-IA carry a 30-day minimum; Glacier Flexible Retrieval carries a 90-day minimum; Deep Archive carries a 180-day minimum. Transitioning before those thresholds does not block the transition, but you will be billed as if the object stayed for the full minimum period. See S3 cost optimisation for how these charges work in practice.
Expiration#
Deletes the current version of an object after a set number of days.
In a non-versioned bucket, expiration permanently removes the object.
In a versioned bucket, expiration adds a delete marker. The object still exists as a noncurrent version: it is hidden in normal listings but still stored and billed. To truly remove versioned objects, you need the two noncurrent-version rules below.
AbortIncompleteMultipartUpload#
S3’s multipart upload feature splits large files into parts uploaded individually. If an upload is interrupted by a network failure, a crashed process, or an abandoned script, the uploaded parts remain in storage and accumulate charges indefinitely. This action automatically cancels any multipart upload that has not completed within a specified number of days after initiation.
NoncurrentVersionTransition#
In versioned buckets, this moves older (noncurrent) versions to a cheaper storage class after they have been noncurrent for a set number of days. Useful for keeping old versions around for recovery without paying Standard prices for all of them.
NoncurrentVersionExpiration#
Permanently deletes noncurrent versions after they have been noncurrent for a set number of days. This is how you stop a versioned bucket from growing indefinitely. Without this rule, every overwrite generates a noncurrent version that sits in storage forever.
ExpiredObjectDeleteMarker#
When a delete marker has no remaining noncurrent versions beneath it, it is considered expired. Without this setting, expired delete markers accumulate and inflate your object count (and therefore your LIST request costs). Setting ExpiredObjectDeleteMarker: true in the expiration block tells S3 to clean these up automatically.
You cannot combine ExpiredObjectDeleteMarker: true with Days in the same expiration block. They are mutually exclusive in the JSON configuration.
Practical examples
Example 1: Log retention with tiered transitions#
A standard pattern for application logs: active for 30 days, reference tier for 90 days, compliance archive until 365 days:
{
"Rules": [
{
"ID": "log-retention-tiered",
"Status": "Enabled",
"Filter": {
"Prefix": "logs/"
},
"Transitions": [
{
"Days": 30,
"StorageClass": "STANDARD_IA"
},
{
"Days": 90,
"StorageClass": "GLACIER"
}
],
"Expiration": {
"Days": 365
}
}
]
}Why this rule exists: logs are queried heavily in the first few days and occasionally over the following months. Past 90 days they are almost never accessed but must be retained for audits. Glacier Flexible Retrieval at day 90 keeps them accessible (with a restore step) at a fraction of Standard pricing. The day 365 expiration prevents indefinite accumulation.
The GLACIER storage class here refers to S3 Glacier Flexible Retrieval. Objects transitioned here cannot be read directly. They must be restored first, which takes 1–12 hours depending on the retrieval tier you request.
Example 2: Versioned bucket cleanup#
For a versioned bucket that receives frequent overwrites, this rule moves noncurrent versions to cheaper storage and eventually deletes them:
{
"Rules": [
{
"ID": "versioned-bucket-cleanup",
"Status": "Enabled",
"Filter": {},
"NoncurrentVersionTransitions": [
{
"NoncurrentDays": 30,
"StorageClass": "STANDARD_IA"
},
{
"NoncurrentDays": 90,
"StorageClass": "GLACIER"
}
],
"NoncurrentVersionExpiration": {
"NoncurrentDays": 365
},
"Expiration": {
"ExpiredObjectDeleteMarker": true
}
}
]
}Why this rule exists: without noncurrent-version management, every overwrite creates a new version that accumulates indefinitely. After 365 days as a noncurrent version, the old copy is permanently deleted. ExpiredObjectDeleteMarker: true prevents leftover delete markers from inflating object counts after the underlying versions are gone.
An empty Filter: {} means this rule applies to every object in the bucket.
Example 3: Incomplete multipart upload cleanup#
Add this to any bucket that receives large file uploads:
{
"Rules": [
{
"ID": "abort-incomplete-multipart",
"Status": "Enabled",
"Filter": {},
"AbortIncompleteMultipartUpload": {
"DaysAfterInitiation": 7
}
}
]
}Why this rule exists: if a large upload fails halfway through, the parts uploaded so far are stored and billed even though the object is never completed. Without this rule, interrupted uploads silently accumulate over time. Seven days is long enough to cover retries; shorter is fine depending on your upload patterns.
You can combine this rule with the others above by adding multiple objects to the Rules array in a single lifecycle configuration.
S3 Lifecycle Policies vs S3 Intelligent-Tiering
Both tools reduce storage costs, but they approach the problem differently.
| S3 Lifecycle Policies | S3 Intelligent-Tiering | |
|---|---|---|
| Best for | Predictable, time-based access patterns | Irregular or unpredictable access |
| How tiering works | You define explicit day thresholds | AWS monitors access and moves automatically |
| Deletion support | Yes: expiration rules delete objects | No: Intelligent-Tiering does not delete |
| Control level | High: you set every transition | Low: AWS makes the decisions |
| Operational overhead | Requires planning and upfront rule design | Set and forget once enabled |
| Monitoring fee | None | Small per-object monitoring fee |
| Retrieval costs | Depend on the target storage class | No retrieval fees between tiers |
If you can draw a timeline and say “this data goes cold at day X”, use lifecycle rules. If you cannot predict when objects will be accessed (or if the same objects are sometimes accessed months later without warning), Intelligent-Tiering is the lower-maintenance option. For data with a defined end-of-life date, lifecycle rules are the only choice since Intelligent-Tiering does not delete objects.
Many teams use both: lifecycle rules for objects with a known retention period, Intelligent-Tiering for long-lived assets with irregular access.
How to create a lifecycle rule
AWS Console#
- Open the S3 console and select your bucket.
- Go to the Management tab.
- Click Create lifecycle rule.
- Enter a rule name and choose the scope: all objects, or a specific prefix/tag filter.
- Select the lifecycle rule actions you want: transitions, expiration, noncurrent-version actions, or incomplete multipart upload cleanup.
- Configure the day thresholds for each action.
- Review the summary and click Create rule.
The console shows a visual timeline as you configure thresholds, which helps verify the rule logic before saving.
AWS CLI#
Save your lifecycle configuration JSON to a file (for example, lifecycle.json), then apply it:
aws s3api put-bucket-lifecycle-configuration \
--bucket your-bucket-name \
--lifecycle-configuration file://lifecycle.jsonTo view the current lifecycle configuration on a bucket:
aws s3api get-bucket-lifecycle-configuration --bucket your-bucket-nameTo delete all lifecycle rules from a bucket:
aws s3api delete-bucket-lifecycle --bucket your-bucket-nameFor large file uploads that use multipart upload, see uploading files with the AWS CLI for how the multipart process works and when the AbortIncompleteMultipartUpload rule becomes important.
The StorageClass values in lifecycle JSON use all-caps with underscores: STANDARD_IA, GLACIER, DEEP_ARCHIVE, INTELLIGENT_TIERING. These differ from the display names shown in the AWS console but are required in the API and CLI.
Common mistakes
Transitioning too early and hitting minimum-duration charges. Each storage class has a minimum billing period: 30 days for Standard-IA, 90 days for Glacier Flexible Retrieval, 180 days for Deep Archive. Transitioning an object to Standard-IA at day 5 does not block the transition, but you will be billed as if it stayed for 30 days. Only transition when the object is likely to remain in that class for at least its minimum period. Check how these charges are calculated before setting aggressive thresholds.
Forgetting that versioning changes expiration behaviour. In a versioned bucket, a standard expiration rule adds a delete marker, not a permanent deletion. You must also configure NoncurrentVersionExpiration rules. Without them, noncurrent versions accumulate indefinitely and storage costs keep growing. This is one of the most common silent cost issues in S3.
Not cleaning up incomplete multipart uploads. This cost is invisible in the console unless you specifically look for in-progress uploads. For any bucket that receives large file uploads, add an AbortIncompleteMultipartUpload rule with a 7-day threshold as a minimum baseline.
Accidentally targeting the whole bucket. Leaving the filter empty applies a lifecycle rule to every object in the bucket. Always set an explicit prefix or tag filter on production buckets unless you genuinely intend bucket-wide coverage. Review filters carefully before enabling a rule.
Assuming archived objects are instantly readable. Objects in Glacier Flexible Retrieval or Deep Archive must be restored before they can be accessed. Restoration to Glacier Flexible Retrieval takes 1–12 hours; Deep Archive takes 12–48 hours. Do not archive data that needs to be available on demand.
Overlooking per-request overhead for large numbers of small objects. Lifecycle transitions generate PUT and DELETE requests. If you have tens of millions of tiny objects (under 128 KB), the per-request overhead and minimum storage charges for IA tiers may outweigh the storage savings. Consider consolidating small objects or using a different retention strategy for high-volume, small-object workloads.
Summary
- Lifecycle policies automate storage-class transitions and object deletion based on object age. No cron jobs or Lambda functions required.
- Rules match objects by prefix, tag, or both. An empty filter matches all objects in the bucket.
- Actions include Transition, Expiration, AbortIncompleteMultipartUpload, NoncurrentVersionTransition, NoncurrentVersionExpiration, and ExpiredObjectDeleteMarker.
- In versioned buckets, expiration adds a delete marker, not a permanent deletion. Add NoncurrentVersionExpiration rules to actually remove old versions.
- Lifecycle actions are processed asynchronously, typically within 24 hours of the configured day threshold.
- Objects in Glacier tiers must be restored before they can be accessed. Plan for retrieval time if you archive data.
- Minimum storage duration charges apply to IA and Glacier tiers. Transitioning too early can increase rather than reduce costs.
- For unpredictable access patterns, S3 Intelligent-Tiering is often a lower-maintenance alternative. Lifecycle rules are the right choice when you need deletion or when access patterns are clearly time-based.
Frequently asked questions
How long do lifecycle rules take to apply?
Lifecycle actions are not instant. AWS typically processes them within 24 hours of the configured day threshold. An object due to transition on day 30 may actually transition any time during or shortly after day 30, but never before it.
Does expiration permanently delete objects in versioned buckets?
No. In a versioned bucket, an expiration action adds a delete marker rather than removing the data. The previous versions are still stored and still billed. To actually remove old data, you need a NoncurrentVersionExpiration rule alongside the expiration rule.
Can lifecycle rules target only some objects in a bucket?
Yes. Rules can be scoped to a key prefix (e.g. logs/ or reports/annual/), to object tags, or to a combination of both using an And filter. Leaving the filter empty applies the rule to every object in the bucket.
Are S3 lifecycle policies or S3 Intelligent-Tiering better?
It depends on your access patterns. If you know exactly when objects go cold (for example, logs older than 30 days), lifecycle rules give you precise control and support deletion. If access is unpredictable or irregular, Intelligent-Tiering automates tier movement without you needing to guess. Many teams use both: lifecycle rules for data with a known retention period, Intelligent-Tiering for long-lived data with variable access.
What happens if two lifecycle rules overlap on the same object?
If multiple rules match the same object, S3 applies the action that results in the lowest cost for the current state. For transitions, it picks the earliest applicable transition. For expiration, the rule with the fewest days takes effect. Avoid overlapping rules where possible, as they are hard to reason about and can produce unexpected behaviour.