Configure AWS S3 Bucket Versioning

The aws:s3/bucketVersioningV2:BucketVersioningV2 resource, part of the Pulumi AWS provider, controls versioning behavior on S3 buckets: enabling, disabling, or suspending version tracking for objects. This guide focuses on two capabilities: enabling and disabling versioning, and coordinating object creation with versioning state.

Versioning resources reference existing S3 buckets and may need to coordinate with object creation timing. The examples are intentionally small. Combine them with your own bucket infrastructure and lifecycle policies.

Enable versioning to preserve object history

Teams protecting against accidental deletions or overwrites enable versioning to preserve every version of every object.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.s3.Bucket("example", {bucket: "example-bucket"});
const exampleBucketAcl = new aws.s3.BucketAcl("example", {
    bucket: example.id,
    acl: "private",
});
const versioningExample = new aws.s3.BucketVersioning("versioning_example", {
    bucket: example.id,
    versioningConfiguration: {
        status: "Enabled",
    },
});
import pulumi
import pulumi_aws as aws

example = aws.s3.Bucket("example", bucket="example-bucket")
example_bucket_acl = aws.s3.BucketAcl("example",
    bucket=example.id,
    acl="private")
versioning_example = aws.s3.BucketVersioning("versioning_example",
    bucket=example.id,
    versioning_configuration={
        "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 {
		example, err := s3.NewBucket(ctx, "example", &s3.BucketArgs{
			Bucket: pulumi.String("example-bucket"),
		})
		if err != nil {
			return err
		}
		_, err = s3.NewBucketAcl(ctx, "example", &s3.BucketAclArgs{
			Bucket: example.ID(),
			Acl:    pulumi.String("private"),
		})
		if err != nil {
			return err
		}
		_, err = s3.NewBucketVersioning(ctx, "versioning_example", &s3.BucketVersioningArgs{
			Bucket: example.ID(),
			VersioningConfiguration: &s3.BucketVersioningVersioningConfigurationArgs{
				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.Bucket("example", new()
    {
        BucketName = "example-bucket",
    });

    var exampleBucketAcl = new Aws.S3.BucketAcl("example", new()
    {
        Bucket = example.Id,
        Acl = "private",
    });

    var versioningExample = new Aws.S3.BucketVersioning("versioning_example", new()
    {
        Bucket = example.Id,
        VersioningConfiguration = new Aws.S3.Inputs.BucketVersioningVersioningConfigurationArgs
        {
            Status = "Enabled",
        },
    });

});
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.BucketVersioning;
import com.pulumi.aws.s3.BucketVersioningArgs;
import com.pulumi.aws.s3.inputs.BucketVersioningVersioningConfigurationArgs;
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 Bucket("example", BucketArgs.builder()
            .bucket("example-bucket")
            .build());

        var exampleBucketAcl = new BucketAcl("exampleBucketAcl", BucketAclArgs.builder()
            .bucket(example.id())
            .acl("private")
            .build());

        var versioningExample = new BucketVersioning("versioningExample", BucketVersioningArgs.builder()
            .bucket(example.id())
            .versioningConfiguration(BucketVersioningVersioningConfigurationArgs.builder()
                .status("Enabled")
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:s3:Bucket
    properties:
      bucket: example-bucket
  exampleBucketAcl:
    type: aws:s3:BucketAcl
    name: example
    properties:
      bucket: ${example.id}
      acl: private
  versioningExample:
    type: aws:s3:BucketVersioning
    name: versioning_example
    properties:
      bucket: ${example.id}
      versioningConfiguration:
        status: Enabled

When versioning is enabled, S3 assigns a unique version ID to each object write. The versioningConfiguration block sets the status property to “Enabled”, which activates version tracking. AWS recommends waiting 15 minutes after enabling versioning before issuing write operations on objects in the bucket.

Disable versioning to stop creating new versions

When versioning is no longer needed, you can disable it to stop creating new versions while preserving existing ones.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.s3.Bucket("example", {bucket: "example-bucket"});
const exampleBucketAcl = new aws.s3.BucketAcl("example", {
    bucket: example.id,
    acl: "private",
});
const versioningExample = new aws.s3.BucketVersioning("versioning_example", {
    bucket: example.id,
    versioningConfiguration: {
        status: "Disabled",
    },
});
import pulumi
import pulumi_aws as aws

example = aws.s3.Bucket("example", bucket="example-bucket")
example_bucket_acl = aws.s3.BucketAcl("example",
    bucket=example.id,
    acl="private")
versioning_example = aws.s3.BucketVersioning("versioning_example",
    bucket=example.id,
    versioning_configuration={
        "status": "Disabled",
    })
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 {
		example, err := s3.NewBucket(ctx, "example", &s3.BucketArgs{
			Bucket: pulumi.String("example-bucket"),
		})
		if err != nil {
			return err
		}
		_, err = s3.NewBucketAcl(ctx, "example", &s3.BucketAclArgs{
			Bucket: example.ID(),
			Acl:    pulumi.String("private"),
		})
		if err != nil {
			return err
		}
		_, err = s3.NewBucketVersioning(ctx, "versioning_example", &s3.BucketVersioningArgs{
			Bucket: example.ID(),
			VersioningConfiguration: &s3.BucketVersioningVersioningConfigurationArgs{
				Status: pulumi.String("Disabled"),
			},
		})
		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.Bucket("example", new()
    {
        BucketName = "example-bucket",
    });

    var exampleBucketAcl = new Aws.S3.BucketAcl("example", new()
    {
        Bucket = example.Id,
        Acl = "private",
    });

    var versioningExample = new Aws.S3.BucketVersioning("versioning_example", new()
    {
        Bucket = example.Id,
        VersioningConfiguration = new Aws.S3.Inputs.BucketVersioningVersioningConfigurationArgs
        {
            Status = "Disabled",
        },
    });

});
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.BucketVersioning;
import com.pulumi.aws.s3.BucketVersioningArgs;
import com.pulumi.aws.s3.inputs.BucketVersioningVersioningConfigurationArgs;
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 Bucket("example", BucketArgs.builder()
            .bucket("example-bucket")
            .build());

        var exampleBucketAcl = new BucketAcl("exampleBucketAcl", BucketAclArgs.builder()
            .bucket(example.id())
            .acl("private")
            .build());

        var versioningExample = new BucketVersioning("versioningExample", BucketVersioningArgs.builder()
            .bucket(example.id())
            .versioningConfiguration(BucketVersioningVersioningConfigurationArgs.builder()
                .status("Disabled")
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:s3:Bucket
    properties:
      bucket: example-bucket
  exampleBucketAcl:
    type: aws:s3:BucketAcl
    name: example
    properties:
      bucket: ${example.id}
      acl: private
  versioningExample:
    type: aws:s3:BucketVersioning
    name: versioning_example
    properties:
      bucket: ${example.id}
      versioningConfiguration:
        status: Disabled

Setting status to “Disabled” suspends versioning: new writes no longer create versions, but existing versions remain accessible. This differs from deleting the versioning resource, which either suspends versioning or removes the resource from state if the bucket was never versioned.

Coordinate object creation with versioning enablement

When creating objects that need version IDs in the same deployment, explicit dependencies ensure versioning is enabled first.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.s3.Bucket("example", {bucket: "yotto"});
const exampleBucketVersioning = new aws.s3.BucketVersioning("example", {
    bucket: example.id,
    versioningConfiguration: {
        status: "Enabled",
    },
});
const exampleBucketObjectv2 = new aws.s3.BucketObjectv2("example", {
    bucket: exampleBucketVersioning.id,
    key: "droeloe",
    source: new pulumi.asset.FileAsset("example.txt"),
});
import pulumi
import pulumi_aws as aws

example = aws.s3.Bucket("example", bucket="yotto")
example_bucket_versioning = aws.s3.BucketVersioning("example",
    bucket=example.id,
    versioning_configuration={
        "status": "Enabled",
    })
example_bucket_objectv2 = aws.s3.BucketObjectv2("example",
    bucket=example_bucket_versioning.id,
    key="droeloe",
    source=pulumi.FileAsset("example.txt"))
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 {
		example, err := s3.NewBucket(ctx, "example", &s3.BucketArgs{
			Bucket: pulumi.String("yotto"),
		})
		if err != nil {
			return err
		}
		exampleBucketVersioning, err := s3.NewBucketVersioning(ctx, "example", &s3.BucketVersioningArgs{
			Bucket: example.ID(),
			VersioningConfiguration: &s3.BucketVersioningVersioningConfigurationArgs{
				Status: pulumi.String("Enabled"),
			},
		})
		if err != nil {
			return err
		}
		_, err = s3.NewBucketObjectv2(ctx, "example", &s3.BucketObjectv2Args{
			Bucket: exampleBucketVersioning.ID(),
			Key:    pulumi.String("droeloe"),
			Source: pulumi.NewFileAsset("example.txt"),
		})
		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.Bucket("example", new()
    {
        BucketName = "yotto",
    });

    var exampleBucketVersioning = new Aws.S3.BucketVersioning("example", new()
    {
        Bucket = example.Id,
        VersioningConfiguration = new Aws.S3.Inputs.BucketVersioningVersioningConfigurationArgs
        {
            Status = "Enabled",
        },
    });

    var exampleBucketObjectv2 = new Aws.S3.BucketObjectv2("example", new()
    {
        Bucket = exampleBucketVersioning.Id,
        Key = "droeloe",
        Source = new FileAsset("example.txt"),
    });

});
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.BucketVersioning;
import com.pulumi.aws.s3.BucketVersioningArgs;
import com.pulumi.aws.s3.inputs.BucketVersioningVersioningConfigurationArgs;
import com.pulumi.aws.s3.BucketObjectv2;
import com.pulumi.aws.s3.BucketObjectv2Args;
import com.pulumi.asset.FileAsset;
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 Bucket("example", BucketArgs.builder()
            .bucket("yotto")
            .build());

        var exampleBucketVersioning = new BucketVersioning("exampleBucketVersioning", BucketVersioningArgs.builder()
            .bucket(example.id())
            .versioningConfiguration(BucketVersioningVersioningConfigurationArgs.builder()
                .status("Enabled")
                .build())
            .build());

        var exampleBucketObjectv2 = new BucketObjectv2("exampleBucketObjectv2", BucketObjectv2Args.builder()
            .bucket(exampleBucketVersioning.id())
            .key("droeloe")
            .source(new FileAsset("example.txt"))
            .build());

    }
}
resources:
  example:
    type: aws:s3:Bucket
    properties:
      bucket: yotto
  exampleBucketVersioning:
    type: aws:s3:BucketVersioning
    name: example
    properties:
      bucket: ${example.id}
      versioningConfiguration:
        status: Enabled
  exampleBucketObjectv2:
    type: aws:s3:BucketObjectv2
    name: example
    properties:
      bucket: ${exampleBucketVersioning.id}
      key: droeloe
      source:
        fn::FileAsset: example.txt

The BucketObjectv2 resource references the versioning resource’s bucket ID, creating an implicit dependency that ensures versioning is active before the object is written. For critical or production objects, AWS recommends creating the bucket and enabling versioning in a separate deployment, waiting 15 minutes, then creating objects in a subsequent deployment.

Beyond these examples

These snippets focus on specific versioning features: versioning state management and object creation coordination. They’re intentionally minimal rather than full bucket configurations.

The examples reference pre-existing infrastructure such as S3 buckets. They focus on versioning configuration rather than provisioning buckets or managing their contents.

To keep things focused, common versioning patterns are omitted, including:

  • MFA delete protection (mfa property)
  • Cross-account bucket access (expectedBucketOwner)
  • Lifecycle policies for version expiration
  • Suspending vs permanently disabling versioning

These omissions are intentional: the goal is to illustrate how versioning state is wired, not provide drop-in bucket modules. See the S3 BucketVersioningV2 resource reference for all available configuration options.

Let's configure AWS S3 Bucket Versioning

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Versioning Configuration & Timing
Why should I wait 15 minutes after enabling versioning?
AWS recommends waiting 15 minutes after enabling versioning before issuing write operations (PUT or DELETE) on objects. For critical or production S3 objects, avoid creating the bucket, enabling versioning, and creating objects in the same configuration to allow this recommended wait time.
How do I enable or disable versioning on an S3 bucket?
Set versioningConfiguration.status to Enabled to turn on versioning, or Disabled to turn it off.
What's the difference between Enabled and Disabled versioning status?
Enabled turns on versioning for new and existing objects, while Disabled prevents new versions from being created (existing versions remain).
Resource Lifecycle & Dependencies
What happens when I delete this versioning resource?
Deleting this resource will either suspend versioning on the S3 bucket (if versioning was enabled) or simply remove the resource from state (if the bucket is unversioned).
How do I ensure my S3 object depends on versioning being enabled?
You can create an implicit dependency by referencing the versioning resource’s bucket property in your object definition, or use explicit dependsOn to ensure versioning is enabled before object creation.
Limitations & Compatibility
Can I use this resource with S3 directory buckets?
No, this resource cannot be used with S3 directory buckets. Use standard S3 buckets only.
What properties can't I change after creating this resource?
The bucket and expectedBucketOwner properties are immutable and cannot be changed after creation.
Cross-Account & Import
How do I import versioning for a bucket owned by another account?
Import using the bucket name and expected bucket owner account ID separated by a comma: bucket-name,123456789012.

Using a different cloud?

Explore storage guides for other cloud providers: