S3 Versioning
Complete guide to object versioning, MFA delete, and version management
S3 versioning enables you to keep multiple variants of an object in the same bucket. This protects against accidental deletions and overwrites.
Understanding Versioning
Key Concepts
- Each object version has a unique Version ID
- Versioning is enabled at the bucket level
- Once enabled, versioning cannot be disabled—only suspended
- All versions are stored and billed as separate objects
Versioning States
A bucket can be in one of three versioning states:
| State | Description | Behavior |
|---|---|---|
| Unversioned | Default state | No version IDs, overwrites replace objects |
| Versioning-Enabled | Versioning active | Each PUT creates new version |
| Versioning-Suspended | Versioning paused | New objects get null version ID |
You cannot return a bucket to unversioned state after enabling versioning.
Enabling Versioning
aws s3api put-bucket-versioning \
--bucket my-bucket \
--versioning-configuration Status=Enabledaws s3api get-bucket-versioning --bucket my-bucketOutput:
{
"Status": "Enabled",
"MFADelete": "Disabled"
}How Versioning Works
Initial Upload
When you upload an object, S3 assigns a unique Version ID:
aws s3 cp report.pdf s3://my-bucket/
# Object now has Version ID: v1ABC123Subsequent Uploads
Each upload creates a new version; previous versions are preserved:
aws s3 cp report-v2.pdf s3://my-bucket/report.pdf
# Creates new version: v2DEF456
# Previous version v1ABC123 still existsAccessing Versions
By default, GET returns the latest version:
aws s3 cp s3://my-bucket/report.pdf ./To get a specific version:
aws s3api get-object \
--bucket my-bucket \
--key report.pdf \
--version-id v1ABC123 \
report-old.pdfListing Object Versions
aws s3api list-object-versions --bucket my-bucket{
"Versions": [
{
"Key": "report.pdf",
"VersionId": "v2DEF456",
"IsLatest": true,
"LastModified": "2024-01-15T10:30:00Z",
"Size": 2048576
},
{
"Key": "report.pdf",
"VersionId": "v1ABC123",
"IsLatest": false,
"LastModified": "2024-01-10T09:00:00Z",
"Size": 1024000
}
],
"DeleteMarkers": []
}aws s3api list-object-versions \
--bucket my-bucket \
--prefix reports/aws s3api list-object-versions \
--bucket my-bucket \
--prefix report.pdf \
--query 'Versions[?Key==`report.pdf`]'aws s3api list-object-versions \
--bucket my-bucket \
--max-keys 100 \
--key-marker "" \
--version-id-marker ""Delete Operations with Versioning
Important
Deleting an object in a versioned bucket doesn't remove it permanently—it creates a delete marker.
Delete Markers
When you delete an object without specifying a version ID:
aws s3 rm s3://my-bucket/report.pdfThis creates a delete marker that becomes the current version. The object appears deleted, but all previous versions still exist.
Restoring Deleted Objects
# Find the delete marker
aws s3api list-object-versions \
--bucket my-bucket \
--prefix report.pdf \
--query 'DeleteMarkers[?IsLatest==`true`].{Key:Key,VersionId:VersionId}'
# Delete the delete marker
aws s3api delete-object \
--bucket my-bucket \
--key report.pdf \
--version-id "DeleteMarkerVersionId123"aws s3api copy-object \
--bucket my-bucket \
--key report.pdf \
--copy-source "my-bucket/report.pdf?versionId=v1ABC123"Permanent Deletion
To permanently delete a specific version:
aws s3api delete-object \
--bucket my-bucket \
--key report.pdf \
--version-id v1ABC123Permanently deleting versions cannot be undone. Use MFA Delete for additional protection.
MFA Delete
MFA Delete provides an additional layer of security for version deletion.
MFA Delete Protection
When enabled, MFA Delete requires:
- Multi-factor authentication to permanently delete object versions
- MFA to change the bucket's versioning state
Enable MFA Delete
MFA Delete can only be enabled by the root account using the AWS CLI:
aws s3api put-bucket-versioning \
--bucket my-bucket \
--versioning-configuration Status=Enabled,MFADelete=Enabled \
--mfa "arn:aws:iam::123456789012:mfa/root-account-mfa-device 123456"Root Account Required
MFA Delete can only be enabled/disabled by the root account, not by IAM users.
Delete with MFA
aws s3api delete-object \
--bucket my-bucket \
--key report.pdf \
--version-id v1ABC123 \
--mfa "arn:aws:iam::123456789012:mfa/root-account-mfa-device 654321"Versioning with Lifecycle Rules
Combine versioning with lifecycle rules to manage costs:
{
"Rules": [
{
"ID": "ExpireOldVersions",
"Status": "Enabled",
"Filter": {},
"NoncurrentVersionExpiration": {
"NoncurrentDays": 90
}
}
]
}{
"Rules": [
{
"ID": "AbortIncompleteUploads",
"Status": "Enabled",
"Filter": {},
"AbortIncompleteMultipartUpload": {
"DaysAfterInitiation": 7
}
}
]
}{
"Rules": [
{
"ID": "ArchiveOldVersions",
"Status": "Enabled",
"Filter": {},
"NoncurrentVersionTransitions": [
{
"NoncurrentDays": 30,
"StorageClass": "STANDARD_IA"
},
{
"NoncurrentDays": 90,
"StorageClass": "GLACIER"
}
],
"NoncurrentVersionExpiration": {
"NoncurrentDays": 365
}
}
]
}aws s3api put-bucket-lifecycle-configuration \
--bucket my-bucket \
--lifecycle-configuration file://lifecycle.jsonKeep Only N Versions
Limit the number of noncurrent versions retained:
{
"Rules": [
{
"ID": "KeepLast3Versions",
"Status": "Enabled",
"Filter": {},
"NoncurrentVersionExpiration": {
"NewerNoncurrentVersions": 3,
"NoncurrentDays": 1
}
}
]
}This keeps only the 3 most recent noncurrent versions and deletes older ones after 1 day of becoming noncurrent.
Expired Delete Markers
When all versions of an object are deleted (only a delete marker remains), you can automatically clean up:
{
"Rules": [
{
"ID": "DeleteExpiredMarkers",
"Status": "Enabled",
"Filter": {},
"Expiration": {
"ExpiredObjectDeleteMarker": true
}
}
]
}Suspending Versioning
Suspending versioning doesn't delete existing versions—it just stops creating new ones.
aws s3api put-bucket-versioning \
--bucket my-bucket \
--versioning-configuration Status=SuspendedWhen suspended:
- Existing versions remain intact
- New object uploads get a
nullVersion ID - Uploading overwrites objects with
nullVersion ID
Version-Specific Operations
aws s3api head-object \
--bucket my-bucket \
--key report.pdf \
--version-id v1ABC123aws s3api put-object-acl \
--bucket my-bucket \
--key report.pdf \
--version-id v1ABC123 \
--acl privatePresigned URLs for Versions
Generate presigned URLs for specific versions:
aws s3 presign \
s3://my-bucket/report.pdf \
--version-id v1ABC123 \
--expires-in 3600Versioning with Replication
Cross-region replication (CRR) and same-region replication (SRR) require versioning enabled on both source and destination buckets.
{
"Role": "arn:aws:iam::123456789012:role/replication-role",
"Rules": [
{
"ID": "ReplicateAll",
"Status": "Enabled",
"Priority": 1,
"Filter": {},
"DeleteMarkerReplication": {
"Status": "Enabled"
},
"Destination": {
"Bucket": "arn:aws:s3:::destination-bucket",
"ReplicaModifications": {
"Status": "Enabled"
}
}
}
]
}Common Use Cases
Backup and Recovery
#!/bin/bash
BUCKET="my-bucket"
BACKUP_BUCKET="my-backup-bucket"
PREFIX="critical/"
aws s3api list-object-versions --bucket $BUCKET --prefix $PREFIX \
--query 'Versions[*].[Key,VersionId]' --output text | \
while read KEY VERSION; do
aws s3api copy-object \
--bucket $BACKUP_BUCKET \
--key "${KEY}/${VERSION}" \
--copy-source "${BUCKET}/${KEY}?versionId=${VERSION}"
doneAudit Trail
Use versioning combined with Object Lock for compliance:
aws s3api create-bucket \
--bucket my-compliance-bucket \
--object-lock-enabled-for-bucket \
--region us-east-1Cost Considerations
Storage Costs
Each version is a complete copy and is billed separately:
- 100 versions of a 1GB file = 100GB billed storage
- Noncurrent versions count toward storage totals
- Delete markers are not charged
Cost optimization strategies:
- Lifecycle rules: Transition old versions to cheaper storage classes
- Version limits: Keep only N recent noncurrent versions
- Clean up delete markers: Remove expired delete markers
- Monitor: Use S3 Storage Lens to track version storage
Best Practices
Versioning Best Practices
- Enable on important buckets - Protection against accidental deletion
- Combine with lifecycle rules - Manage costs by expiring old versions
- Enable MFA Delete - Protect against malicious deletion
- Monitor storage growth - Versions add up quickly
- Use for compliance - Pair with Object Lock for WORM
- Replicate versions - Enable replication for DR
- Document retention policies - Know how many versions to keep