The aws:s3/bucketLifecycleConfigurationV2:BucketLifecycleConfigurationV2 resource, part of the Pulumi AWS provider, defines lifecycle rules that transition objects between storage classes or delete them based on age, size, tags, or version status. This guide focuses on three capabilities: filter targeting by prefix, tags, and object size; storage class transitions and expiration; and version-aware lifecycle management.
Lifecycle configurations attach to existing S3 buckets. Rules that manage noncurrent versions require BucketVersioning to be enabled first. The examples are intentionally small. Combine them with your own bucket resources and transition schedules.
Apply lifecycle rules to objects by prefix
Most lifecycle configurations target specific object paths, such as logs or temporary data that should move to cheaper storage or expire.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.s3.BucketLifecycleConfiguration("example", {
bucket: bucket.bucket,
rules: [{
id: "rule-1",
filter: {
prefix: "logs/",
},
status: "Enabled",
}],
});
import pulumi
import pulumi_aws as aws
example = aws.s3.BucketLifecycleConfiguration("example",
bucket=bucket["bucket"],
rules=[{
"id": "rule-1",
"filter": {
"prefix": "logs/",
},
"status": "Enabled",
}])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := s3.NewBucketLifecycleConfiguration(ctx, "example", &s3.BucketLifecycleConfigurationArgs{
Bucket: pulumi.Any(bucket.Bucket),
Rules: s3.BucketLifecycleConfigurationRuleArray{
&s3.BucketLifecycleConfigurationRuleArgs{
Id: pulumi.String("rule-1"),
Filter: &s3.BucketLifecycleConfigurationRuleFilterArgs{
Prefix: pulumi.String("logs/"),
},
Status: pulumi.String("Enabled"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.S3.BucketLifecycleConfiguration("example", new()
{
Bucket = bucket.Bucket,
Rules = new[]
{
new Aws.S3.Inputs.BucketLifecycleConfigurationRuleArgs
{
Id = "rule-1",
Filter = new Aws.S3.Inputs.BucketLifecycleConfigurationRuleFilterArgs
{
Prefix = "logs/",
},
Status = "Enabled",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.s3.BucketLifecycleConfiguration;
import com.pulumi.aws.s3.BucketLifecycleConfigurationArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleFilterArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new BucketLifecycleConfiguration("example", BucketLifecycleConfigurationArgs.builder()
.bucket(bucket.bucket())
.rules(BucketLifecycleConfigurationRuleArgs.builder()
.id("rule-1")
.filter(BucketLifecycleConfigurationRuleFilterArgs.builder()
.prefix("logs/")
.build())
.status("Enabled")
.build())
.build());
}
}
resources:
example:
type: aws:s3:BucketLifecycleConfiguration
properties:
bucket: ${bucket.bucket}
rules:
- id: rule-1
filter:
prefix: logs/
status: Enabled
The filter property narrows which objects the rule affects. Setting prefix to “logs/” means the rule applies only to objects whose keys start with that path. The id and status properties identify and enable the rule. Without transition or expiration actions, this rule does nothing; add those to define what happens to matching objects.
Target objects by tag for lifecycle actions
Applications that tag objects can use those tags to control lifecycle behavior, applying different retention to production versus staging data.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.s3.BucketLifecycleConfiguration("example", {
bucket: bucket.bucket,
rules: [{
id: "rule-1",
filter: {
tag: {
key: "Name",
value: "Staging",
},
},
status: "Enabled",
}],
});
import pulumi
import pulumi_aws as aws
example = aws.s3.BucketLifecycleConfiguration("example",
bucket=bucket["bucket"],
rules=[{
"id": "rule-1",
"filter": {
"tag": {
"key": "Name",
"value": "Staging",
},
},
"status": "Enabled",
}])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := s3.NewBucketLifecycleConfiguration(ctx, "example", &s3.BucketLifecycleConfigurationArgs{
Bucket: pulumi.Any(bucket.Bucket),
Rules: s3.BucketLifecycleConfigurationRuleArray{
&s3.BucketLifecycleConfigurationRuleArgs{
Id: pulumi.String("rule-1"),
Filter: &s3.BucketLifecycleConfigurationRuleFilterArgs{
Tag: &s3.BucketLifecycleConfigurationRuleFilterTagArgs{
Key: pulumi.String("Name"),
Value: pulumi.String("Staging"),
},
},
Status: pulumi.String("Enabled"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.S3.BucketLifecycleConfiguration("example", new()
{
Bucket = bucket.Bucket,
Rules = new[]
{
new Aws.S3.Inputs.BucketLifecycleConfigurationRuleArgs
{
Id = "rule-1",
Filter = new Aws.S3.Inputs.BucketLifecycleConfigurationRuleFilterArgs
{
Tag = new Aws.S3.Inputs.BucketLifecycleConfigurationRuleFilterTagArgs
{
Key = "Name",
Value = "Staging",
},
},
Status = "Enabled",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.s3.BucketLifecycleConfiguration;
import com.pulumi.aws.s3.BucketLifecycleConfigurationArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleFilterArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleFilterTagArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new BucketLifecycleConfiguration("example", BucketLifecycleConfigurationArgs.builder()
.bucket(bucket.bucket())
.rules(BucketLifecycleConfigurationRuleArgs.builder()
.id("rule-1")
.filter(BucketLifecycleConfigurationRuleFilterArgs.builder()
.tag(BucketLifecycleConfigurationRuleFilterTagArgs.builder()
.key("Name")
.value("Staging")
.build())
.build())
.status("Enabled")
.build())
.build());
}
}
resources:
example:
type: aws:s3:BucketLifecycleConfiguration
properties:
bucket: ${bucket.bucket}
rules:
- id: rule-1
filter:
tag:
key: Name
value: Staging
status: Enabled
The filter.tag property matches objects with a specific key-value pair. Here, only objects tagged “Name=Staging” are affected. This lets you apply different lifecycle policies to objects in the same bucket based on classification metadata rather than path structure.
Combine prefix and tags for precise targeting
Complex environments often need rules that match both a path pattern and specific tags.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.s3.BucketLifecycleConfiguration("example", {
bucket: bucket.bucket,
rules: [{
id: "rule-1",
filter: {
and: {
prefix: "logs/",
tags: {
Key1: "Value1",
Key2: "Value2",
},
},
},
status: "Enabled",
}],
});
import pulumi
import pulumi_aws as aws
example = aws.s3.BucketLifecycleConfiguration("example",
bucket=bucket["bucket"],
rules=[{
"id": "rule-1",
"filter": {
"and_": {
"prefix": "logs/",
"tags": {
"Key1": "Value1",
"Key2": "Value2",
},
},
},
"status": "Enabled",
}])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := s3.NewBucketLifecycleConfiguration(ctx, "example", &s3.BucketLifecycleConfigurationArgs{
Bucket: pulumi.Any(bucket.Bucket),
Rules: s3.BucketLifecycleConfigurationRuleArray{
&s3.BucketLifecycleConfigurationRuleArgs{
Id: pulumi.String("rule-1"),
Filter: &s3.BucketLifecycleConfigurationRuleFilterArgs{
And: &s3.BucketLifecycleConfigurationRuleFilterAndArgs{
Prefix: pulumi.String("logs/"),
Tags: pulumi.StringMap{
"Key1": pulumi.String("Value1"),
"Key2": pulumi.String("Value2"),
},
},
},
Status: pulumi.String("Enabled"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.S3.BucketLifecycleConfiguration("example", new()
{
Bucket = bucket.Bucket,
Rules = new[]
{
new Aws.S3.Inputs.BucketLifecycleConfigurationRuleArgs
{
Id = "rule-1",
Filter = new Aws.S3.Inputs.BucketLifecycleConfigurationRuleFilterArgs
{
And = new Aws.S3.Inputs.BucketLifecycleConfigurationRuleFilterAndArgs
{
Prefix = "logs/",
Tags =
{
{ "Key1", "Value1" },
{ "Key2", "Value2" },
},
},
},
Status = "Enabled",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.s3.BucketLifecycleConfiguration;
import com.pulumi.aws.s3.BucketLifecycleConfigurationArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleFilterArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleFilterAndArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new BucketLifecycleConfiguration("example", BucketLifecycleConfigurationArgs.builder()
.bucket(bucket.bucket())
.rules(BucketLifecycleConfigurationRuleArgs.builder()
.id("rule-1")
.filter(BucketLifecycleConfigurationRuleFilterArgs.builder()
.and(BucketLifecycleConfigurationRuleFilterAndArgs.builder()
.prefix("logs/")
.tags(Map.ofEntries(
Map.entry("Key1", "Value1"),
Map.entry("Key2", "Value2")
))
.build())
.build())
.status("Enabled")
.build())
.build());
}
}
resources:
example:
type: aws:s3:BucketLifecycleConfiguration
properties:
bucket: ${bucket.bucket}
rules:
- id: rule-1
filter:
and:
prefix: logs/
tags:
Key1: Value1
Key2: Value2
status: Enabled
The and block combines multiple filter criteria. Both prefix and tags must match for the rule to apply. This prevents accidentally affecting objects that share a prefix but lack the required tags, or vice versa.
Control transitions for small objects
S3 applies a default 128 KB minimum for storage class transitions. To transition smaller objects, set an explicit size threshold.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.s3.BucketLifecycleConfiguration("example", {
bucket: bucket.bucket,
rules: [{
id: "Allow small object transitions",
filter: {
objectSizeGreaterThan: 1,
},
status: "Enabled",
transitions: [{
days: 365,
storageClass: "GLACIER_IR",
}],
}],
});
import pulumi
import pulumi_aws as aws
example = aws.s3.BucketLifecycleConfiguration("example",
bucket=bucket["bucket"],
rules=[{
"id": "Allow small object transitions",
"filter": {
"object_size_greater_than": 1,
},
"status": "Enabled",
"transitions": [{
"days": 365,
"storage_class": "GLACIER_IR",
}],
}])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := s3.NewBucketLifecycleConfiguration(ctx, "example", &s3.BucketLifecycleConfigurationArgs{
Bucket: pulumi.Any(bucket.Bucket),
Rules: s3.BucketLifecycleConfigurationRuleArray{
&s3.BucketLifecycleConfigurationRuleArgs{
Id: pulumi.String("Allow small object transitions"),
Filter: &s3.BucketLifecycleConfigurationRuleFilterArgs{
ObjectSizeGreaterThan: pulumi.Int(1),
},
Status: pulumi.String("Enabled"),
Transitions: s3.BucketLifecycleConfigurationRuleTransitionArray{
&s3.BucketLifecycleConfigurationRuleTransitionArgs{
Days: pulumi.Int(365),
StorageClass: pulumi.String("GLACIER_IR"),
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.S3.BucketLifecycleConfiguration("example", new()
{
Bucket = bucket.Bucket,
Rules = new[]
{
new Aws.S3.Inputs.BucketLifecycleConfigurationRuleArgs
{
Id = "Allow small object transitions",
Filter = new Aws.S3.Inputs.BucketLifecycleConfigurationRuleFilterArgs
{
ObjectSizeGreaterThan = 1,
},
Status = "Enabled",
Transitions = new[]
{
new Aws.S3.Inputs.BucketLifecycleConfigurationRuleTransitionArgs
{
Days = 365,
StorageClass = "GLACIER_IR",
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.s3.BucketLifecycleConfiguration;
import com.pulumi.aws.s3.BucketLifecycleConfigurationArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleFilterArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new BucketLifecycleConfiguration("example", BucketLifecycleConfigurationArgs.builder()
.bucket(bucket.bucket())
.rules(BucketLifecycleConfigurationRuleArgs.builder()
.id("Allow small object transitions")
.filter(BucketLifecycleConfigurationRuleFilterArgs.builder()
.objectSizeGreaterThan(1)
.build())
.status("Enabled")
.transitions(BucketLifecycleConfigurationRuleTransitionArgs.builder()
.days(365)
.storageClass("GLACIER_IR")
.build())
.build())
.build());
}
}
resources:
example:
type: aws:s3:BucketLifecycleConfiguration
properties:
bucket: ${bucket.bucket}
rules:
- id: Allow small object transitions
filter:
objectSizeGreaterThan: 1
status: Enabled
transitions:
- days: 365
storageClass: GLACIER_IR
The objectSizeGreaterThan property overrides the default 128 KB minimum. Setting it to 1 byte allows any object to transition. The transitions array defines when objects move to cheaper storage classes; here, objects move to GLACIER_IR after 365 days. Without this size filter, objects under 128 KB would never transition regardless of age.
Manage current and noncurrent object versions
Versioned buckets accumulate old object versions. Lifecycle rules can transition or delete noncurrent versions while preserving recent ones.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const bucket = new aws.s3.Bucket("bucket", {bucket: "my-bucket"});
const bucketAcl = new aws.s3.BucketAcl("bucket_acl", {
bucket: bucket.bucket,
acl: "private",
});
const bucket_config = new aws.s3.BucketLifecycleConfiguration("bucket-config", {
bucket: bucket.bucket,
rules: [
{
id: "log",
expiration: {
days: 90,
},
filter: {
and: {
prefix: "log/",
tags: {
rule: "log",
autoclean: "true",
},
},
},
status: "Enabled",
transitions: [
{
days: 30,
storageClass: "STANDARD_IA",
},
{
days: 60,
storageClass: "GLACIER",
},
],
},
{
id: "tmp",
filter: {
prefix: "tmp/",
},
expiration: {
date: "2023-01-13T00:00:00Z",
},
status: "Enabled",
},
],
});
const versioningBucket = new aws.s3.Bucket("versioning_bucket", {bucket: "my-versioning-bucket"});
const versioningBucketAcl = new aws.s3.BucketAcl("versioning_bucket_acl", {
bucket: versioningBucket.bucket,
acl: "private",
});
const versioning = new aws.s3.BucketVersioning("versioning", {
bucket: versioningBucket.bucket,
versioningConfiguration: {
status: "Enabled",
},
});
const versioning_bucket_config = new aws.s3.BucketLifecycleConfiguration("versioning-bucket-config", {
bucket: versioningBucket.bucket,
rules: [{
id: "config",
filter: {
prefix: "config/",
},
noncurrentVersionExpiration: {
noncurrentDays: 90,
},
noncurrentVersionTransitions: [
{
noncurrentDays: 30,
storageClass: "STANDARD_IA",
},
{
noncurrentDays: 60,
storageClass: "GLACIER",
},
],
status: "Enabled",
}],
}, {
dependsOn: [versioning],
});
import pulumi
import pulumi_aws as aws
bucket = aws.s3.Bucket("bucket", bucket="my-bucket")
bucket_acl = aws.s3.BucketAcl("bucket_acl",
bucket=bucket.bucket,
acl="private")
bucket_config = aws.s3.BucketLifecycleConfiguration("bucket-config",
bucket=bucket.bucket,
rules=[
{
"id": "log",
"expiration": {
"days": 90,
},
"filter": {
"and_": {
"prefix": "log/",
"tags": {
"rule": "log",
"autoclean": "true",
},
},
},
"status": "Enabled",
"transitions": [
{
"days": 30,
"storage_class": "STANDARD_IA",
},
{
"days": 60,
"storage_class": "GLACIER",
},
],
},
{
"id": "tmp",
"filter": {
"prefix": "tmp/",
},
"expiration": {
"date": "2023-01-13T00:00:00Z",
},
"status": "Enabled",
},
])
versioning_bucket = aws.s3.Bucket("versioning_bucket", bucket="my-versioning-bucket")
versioning_bucket_acl = aws.s3.BucketAcl("versioning_bucket_acl",
bucket=versioning_bucket.bucket,
acl="private")
versioning = aws.s3.BucketVersioning("versioning",
bucket=versioning_bucket.bucket,
versioning_configuration={
"status": "Enabled",
})
versioning_bucket_config = aws.s3.BucketLifecycleConfiguration("versioning-bucket-config",
bucket=versioning_bucket.bucket,
rules=[{
"id": "config",
"filter": {
"prefix": "config/",
},
"noncurrent_version_expiration": {
"noncurrent_days": 90,
},
"noncurrent_version_transitions": [
{
"noncurrent_days": 30,
"storage_class": "STANDARD_IA",
},
{
"noncurrent_days": 60,
"storage_class": "GLACIER",
},
],
"status": "Enabled",
}],
opts = pulumi.ResourceOptions(depends_on=[versioning]))
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
bucket, err := s3.NewBucket(ctx, "bucket", &s3.BucketArgs{
Bucket: pulumi.String("my-bucket"),
})
if err != nil {
return err
}
_, err = s3.NewBucketAcl(ctx, "bucket_acl", &s3.BucketAclArgs{
Bucket: bucket.Bucket,
Acl: pulumi.String("private"),
})
if err != nil {
return err
}
_, err = s3.NewBucketLifecycleConfiguration(ctx, "bucket-config", &s3.BucketLifecycleConfigurationArgs{
Bucket: bucket.Bucket,
Rules: s3.BucketLifecycleConfigurationRuleArray{
&s3.BucketLifecycleConfigurationRuleArgs{
Id: pulumi.String("log"),
Expiration: &s3.BucketLifecycleConfigurationRuleExpirationArgs{
Days: pulumi.Int(90),
},
Filter: &s3.BucketLifecycleConfigurationRuleFilterArgs{
And: &s3.BucketLifecycleConfigurationRuleFilterAndArgs{
Prefix: pulumi.String("log/"),
Tags: pulumi.StringMap{
"rule": pulumi.String("log"),
"autoclean": pulumi.String("true"),
},
},
},
Status: pulumi.String("Enabled"),
Transitions: s3.BucketLifecycleConfigurationRuleTransitionArray{
&s3.BucketLifecycleConfigurationRuleTransitionArgs{
Days: pulumi.Int(30),
StorageClass: pulumi.String("STANDARD_IA"),
},
&s3.BucketLifecycleConfigurationRuleTransitionArgs{
Days: pulumi.Int(60),
StorageClass: pulumi.String("GLACIER"),
},
},
},
&s3.BucketLifecycleConfigurationRuleArgs{
Id: pulumi.String("tmp"),
Filter: &s3.BucketLifecycleConfigurationRuleFilterArgs{
Prefix: pulumi.String("tmp/"),
},
Expiration: &s3.BucketLifecycleConfigurationRuleExpirationArgs{
Date: pulumi.String("2023-01-13T00:00:00Z"),
},
Status: pulumi.String("Enabled"),
},
},
})
if err != nil {
return err
}
versioningBucket, err := s3.NewBucket(ctx, "versioning_bucket", &s3.BucketArgs{
Bucket: pulumi.String("my-versioning-bucket"),
})
if err != nil {
return err
}
_, err = s3.NewBucketAcl(ctx, "versioning_bucket_acl", &s3.BucketAclArgs{
Bucket: versioningBucket.Bucket,
Acl: pulumi.String("private"),
})
if err != nil {
return err
}
versioning, err := s3.NewBucketVersioning(ctx, "versioning", &s3.BucketVersioningArgs{
Bucket: versioningBucket.Bucket,
VersioningConfiguration: &s3.BucketVersioningVersioningConfigurationArgs{
Status: pulumi.String("Enabled"),
},
})
if err != nil {
return err
}
_, err = s3.NewBucketLifecycleConfiguration(ctx, "versioning-bucket-config", &s3.BucketLifecycleConfigurationArgs{
Bucket: versioningBucket.Bucket,
Rules: s3.BucketLifecycleConfigurationRuleArray{
&s3.BucketLifecycleConfigurationRuleArgs{
Id: pulumi.String("config"),
Filter: &s3.BucketLifecycleConfigurationRuleFilterArgs{
Prefix: pulumi.String("config/"),
},
NoncurrentVersionExpiration: &s3.BucketLifecycleConfigurationRuleNoncurrentVersionExpirationArgs{
NoncurrentDays: pulumi.Int(90),
},
NoncurrentVersionTransitions: s3.BucketLifecycleConfigurationRuleNoncurrentVersionTransitionArray{
&s3.BucketLifecycleConfigurationRuleNoncurrentVersionTransitionArgs{
NoncurrentDays: pulumi.Int(30),
StorageClass: pulumi.String("STANDARD_IA"),
},
&s3.BucketLifecycleConfigurationRuleNoncurrentVersionTransitionArgs{
NoncurrentDays: pulumi.Int(60),
StorageClass: pulumi.String("GLACIER"),
},
},
Status: pulumi.String("Enabled"),
},
},
}, pulumi.DependsOn([]pulumi.Resource{
versioning,
}))
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var bucket = new Aws.S3.Bucket("bucket", new()
{
BucketName = "my-bucket",
});
var bucketAcl = new Aws.S3.BucketAcl("bucket_acl", new()
{
Bucket = bucket.BucketName,
Acl = "private",
});
var bucket_config = new Aws.S3.BucketLifecycleConfiguration("bucket-config", new()
{
Bucket = bucket.BucketName,
Rules = new[]
{
new Aws.S3.Inputs.BucketLifecycleConfigurationRuleArgs
{
Id = "log",
Expiration = new Aws.S3.Inputs.BucketLifecycleConfigurationRuleExpirationArgs
{
Days = 90,
},
Filter = new Aws.S3.Inputs.BucketLifecycleConfigurationRuleFilterArgs
{
And = new Aws.S3.Inputs.BucketLifecycleConfigurationRuleFilterAndArgs
{
Prefix = "log/",
Tags =
{
{ "rule", "log" },
{ "autoclean", "true" },
},
},
},
Status = "Enabled",
Transitions = new[]
{
new Aws.S3.Inputs.BucketLifecycleConfigurationRuleTransitionArgs
{
Days = 30,
StorageClass = "STANDARD_IA",
},
new Aws.S3.Inputs.BucketLifecycleConfigurationRuleTransitionArgs
{
Days = 60,
StorageClass = "GLACIER",
},
},
},
new Aws.S3.Inputs.BucketLifecycleConfigurationRuleArgs
{
Id = "tmp",
Filter = new Aws.S3.Inputs.BucketLifecycleConfigurationRuleFilterArgs
{
Prefix = "tmp/",
},
Expiration = new Aws.S3.Inputs.BucketLifecycleConfigurationRuleExpirationArgs
{
Date = "2023-01-13T00:00:00Z",
},
Status = "Enabled",
},
},
});
var versioningBucket = new Aws.S3.Bucket("versioning_bucket", new()
{
BucketName = "my-versioning-bucket",
});
var versioningBucketAcl = new Aws.S3.BucketAcl("versioning_bucket_acl", new()
{
Bucket = versioningBucket.BucketName,
Acl = "private",
});
var versioning = new Aws.S3.BucketVersioning("versioning", new()
{
Bucket = versioningBucket.BucketName,
VersioningConfiguration = new Aws.S3.Inputs.BucketVersioningVersioningConfigurationArgs
{
Status = "Enabled",
},
});
var versioning_bucket_config = new Aws.S3.BucketLifecycleConfiguration("versioning-bucket-config", new()
{
Bucket = versioningBucket.BucketName,
Rules = new[]
{
new Aws.S3.Inputs.BucketLifecycleConfigurationRuleArgs
{
Id = "config",
Filter = new Aws.S3.Inputs.BucketLifecycleConfigurationRuleFilterArgs
{
Prefix = "config/",
},
NoncurrentVersionExpiration = new Aws.S3.Inputs.BucketLifecycleConfigurationRuleNoncurrentVersionExpirationArgs
{
NoncurrentDays = 90,
},
NoncurrentVersionTransitions = new[]
{
new Aws.S3.Inputs.BucketLifecycleConfigurationRuleNoncurrentVersionTransitionArgs
{
NoncurrentDays = 30,
StorageClass = "STANDARD_IA",
},
new Aws.S3.Inputs.BucketLifecycleConfigurationRuleNoncurrentVersionTransitionArgs
{
NoncurrentDays = 60,
StorageClass = "GLACIER",
},
},
Status = "Enabled",
},
},
}, new CustomResourceOptions
{
DependsOn =
{
versioning,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.s3.Bucket;
import com.pulumi.aws.s3.BucketArgs;
import com.pulumi.aws.s3.BucketAcl;
import com.pulumi.aws.s3.BucketAclArgs;
import com.pulumi.aws.s3.BucketLifecycleConfiguration;
import com.pulumi.aws.s3.BucketLifecycleConfigurationArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleExpirationArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleFilterArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleFilterAndArgs;
import com.pulumi.aws.s3.BucketVersioning;
import com.pulumi.aws.s3.BucketVersioningArgs;
import com.pulumi.aws.s3.inputs.BucketVersioningVersioningConfigurationArgs;
import com.pulumi.aws.s3.inputs.BucketLifecycleConfigurationRuleNoncurrentVersionExpirationArgs;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var bucket = new Bucket("bucket", BucketArgs.builder()
.bucket("my-bucket")
.build());
var bucketAcl = new BucketAcl("bucketAcl", BucketAclArgs.builder()
.bucket(bucket.bucket())
.acl("private")
.build());
var bucket_config = new BucketLifecycleConfiguration("bucket-config", BucketLifecycleConfigurationArgs.builder()
.bucket(bucket.bucket())
.rules(
BucketLifecycleConfigurationRuleArgs.builder()
.id("log")
.expiration(BucketLifecycleConfigurationRuleExpirationArgs.builder()
.days(90)
.build())
.filter(BucketLifecycleConfigurationRuleFilterArgs.builder()
.and(BucketLifecycleConfigurationRuleFilterAndArgs.builder()
.prefix("log/")
.tags(Map.ofEntries(
Map.entry("rule", "log"),
Map.entry("autoclean", "true")
))
.build())
.build())
.status("Enabled")
.transitions(
BucketLifecycleConfigurationRuleTransitionArgs.builder()
.days(30)
.storageClass("STANDARD_IA")
.build(),
BucketLifecycleConfigurationRuleTransitionArgs.builder()
.days(60)
.storageClass("GLACIER")
.build())
.build(),
BucketLifecycleConfigurationRuleArgs.builder()
.id("tmp")
.filter(BucketLifecycleConfigurationRuleFilterArgs.builder()
.prefix("tmp/")
.build())
.expiration(BucketLifecycleConfigurationRuleExpirationArgs.builder()
.date("2023-01-13T00:00:00Z")
.build())
.status("Enabled")
.build())
.build());
var versioningBucket = new Bucket("versioningBucket", BucketArgs.builder()
.bucket("my-versioning-bucket")
.build());
var versioningBucketAcl = new BucketAcl("versioningBucketAcl", BucketAclArgs.builder()
.bucket(versioningBucket.bucket())
.acl("private")
.build());
var versioning = new BucketVersioning("versioning", BucketVersioningArgs.builder()
.bucket(versioningBucket.bucket())
.versioningConfiguration(BucketVersioningVersioningConfigurationArgs.builder()
.status("Enabled")
.build())
.build());
var versioning_bucket_config = new BucketLifecycleConfiguration("versioning-bucket-config", BucketLifecycleConfigurationArgs.builder()
.bucket(versioningBucket.bucket())
.rules(BucketLifecycleConfigurationRuleArgs.builder()
.id("config")
.filter(BucketLifecycleConfigurationRuleFilterArgs.builder()
.prefix("config/")
.build())
.noncurrentVersionExpiration(BucketLifecycleConfigurationRuleNoncurrentVersionExpirationArgs.builder()
.noncurrentDays(90)
.build())
.noncurrentVersionTransitions(
BucketLifecycleConfigurationRuleNoncurrentVersionTransitionArgs.builder()
.noncurrentDays(30)
.storageClass("STANDARD_IA")
.build(),
BucketLifecycleConfigurationRuleNoncurrentVersionTransitionArgs.builder()
.noncurrentDays(60)
.storageClass("GLACIER")
.build())
.status("Enabled")
.build())
.build(), CustomResourceOptions.builder()
.dependsOn(versioning)
.build());
}
}
resources:
bucket:
type: aws:s3:Bucket
properties:
bucket: my-bucket
bucketAcl:
type: aws:s3:BucketAcl
name: bucket_acl
properties:
bucket: ${bucket.bucket}
acl: private
bucket-config:
type: aws:s3:BucketLifecycleConfiguration
properties:
bucket: ${bucket.bucket}
rules:
- id: log
expiration:
days: 90
filter:
and:
prefix: log/
tags:
rule: log
autoclean: 'true'
status: Enabled
transitions:
- days: 30
storageClass: STANDARD_IA
- days: 60
storageClass: GLACIER
- id: tmp
filter:
prefix: tmp/
expiration:
date: 2023-01-13T00:00:00Z
status: Enabled
versioningBucket:
type: aws:s3:Bucket
name: versioning_bucket
properties:
bucket: my-versioning-bucket
versioningBucketAcl:
type: aws:s3:BucketAcl
name: versioning_bucket_acl
properties:
bucket: ${versioningBucket.bucket}
acl: private
versioning:
type: aws:s3:BucketVersioning
properties:
bucket: ${versioningBucket.bucket}
versioningConfiguration:
status: Enabled
versioning-bucket-config:
type: aws:s3:BucketLifecycleConfiguration
properties:
bucket: ${versioningBucket.bucket}
rules:
- id: config
filter:
prefix: config/
noncurrentVersionExpiration:
noncurrentDays: 90
noncurrentVersionTransitions:
- noncurrentDays: 30
storageClass: STANDARD_IA
- noncurrentDays: 60
storageClass: GLACIER
status: Enabled
options:
dependsOn:
- ${versioning}
The noncurrentVersionExpiration and noncurrentVersionTransitions properties manage old versions separately from current ones. Noncurrent versions transition to STANDARD_IA after 30 days, then GLACIER after 60, and expire after 90. Current versions follow the transitions and expiration rules. The dependsOn ensures versioning is enabled before applying lifecycle rules; without versioning, noncurrent version properties have no effect.
Beyond these examples
These snippets focus on specific lifecycle rule features: filter targeting, storage class transitions and expiration, and versioned object lifecycle management. They’re intentionally minimal rather than full bucket configurations.
The examples reference pre-existing infrastructure such as S3 buckets and BucketVersioning resources for version-aware examples. They focus on configuring lifecycle rules rather than provisioning buckets or enabling features.
To keep things focused, common lifecycle patterns are omitted, including:
- Abort incomplete multipart uploads (abortIncompleteMultipartUpload)
- Date-based expiration (expiration.date)
- Multiple rules with different prefixes in one configuration
- ExpiredObjectDeleteMarker cleanup
These omissions are intentional: the goal is to illustrate how each lifecycle feature is wired, not provide drop-in storage management modules. See the S3 Bucket Lifecycle Configuration resource reference for all available configuration options.
Let's configure AWS S3 Bucket Lifecycle Rules
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Common Pitfalls & Limitations
BucketLifecycleConfiguration resources for the same bucket causes perpetual differences. Use one resource with multiple rules instead.objectSizeGreaterThan: 1 to your rule.Filtering & Rule Scope
filter property entirely or set filter: {}. Both approaches apply the rule to all objects in the bucket.filter.prefix to your desired prefix (e.g., logs/). To apply different rules to different prefixes, create separate rules with different prefix values.filter.tag with key and value. For multiple tags, wrap them in filter.and.tags.prefix and tags in the filter.and configuration block to apply the rule only to objects matching both criteria.objectSizeGreaterThan for minimum size or objectSizeLessThan for maximum size (values in bytes, max 5TB). For a size range, use both within filter.and, ensuring objectSizeGreaterThan is less than objectSizeLessThan.Versioning & Noncurrent Objects
noncurrentVersionExpiration to expire old versions and noncurrentVersionTransitions to transition them to different storage classes. Add dependsOn: [versioning] to ensure versioning is enabled before applying lifecycle rules.Configuration & Defaults
all_storage_classes_128K (default) and varies_by_storage_class. Custom filters with objectSizeGreaterThan or objectSizeLessThan always take precedence over this default.