AWS for DevOps — S3 Versioning & Lifecycle

2 minute read

5.2 — S3 Versioning & Lifecycle

Versioning protects against accidental deletes. Lifecycle policies automatically move or expire objects to save costs.

Versioning

When versioning is enabled, S3 keeps every version of every object:

  s3://my-bucket/config.yaml
  ├── Version: v3 (current)  ← what you see by default
  ├── Version: v2
  └── Version: v1
# Enable versioning
$ aws s3api put-bucket-versioning \
    --bucket my-devops-artefacts-2026 \
    --versioning-configuration Status=Enabled

# Upload a file (creates version 1)
$ aws s3 cp config.yaml s3://my-devops-artefacts-2026/config.yaml

# Upload again (creates version 2 — version 1 is preserved)
$ aws s3 cp config-updated.yaml s3://my-devops-artefacts-2026/config.yaml

# List all versions
$ aws s3api list-object-versions \
    --bucket my-devops-artefacts-2026 \
    --prefix config.yaml \
    --query 'Versions[*].[Key,VersionId,IsLatest,LastModified]' \
    --output table
---------------------------------------------------------------
| config.yaml | abc123 | True  | 2026-03-30T10:30:00Z |
| config.yaml | def456 | False | 2026-03-30T10:00:00Z |
---------------------------------------------------------------

# Retrieve a specific version
$ aws s3api get-object \
    --bucket my-devops-artefacts-2026 \
    --key config.yaml \
    --version-id def456 \
    config-v1.yaml

How Deletes Work with Versioning

When you “delete” a versioned object, S3 adds a delete marker — the previous versions still exist:

# "Delete" the object
$ aws s3 rm s3://my-devops-artefacts-2026/config.yaml

# The object appears deleted, but versions are still there
$ aws s3api list-object-versions \
    --bucket my-devops-artefacts-2026 \
    --prefix config.yaml
# Shows: DeleteMarker (latest) + all previous versions

# Restore by deleting the delete marker
$ aws s3api delete-object \
    --bucket my-devops-artefacts-2026 \
    --key config.yaml \
    --version-id <delete-marker-version-id>

Lifecycle Policies

Lifecycle rules automatically transition or expire objects:

$ aws s3api put-bucket-lifecycle-configuration \
    --bucket my-devops-artefacts-2026 \
    --lifecycle-configuration '{
        "Rules": [
            {
                "ID": "ArchiveOldBuilds",
                "Status": "Enabled",
                "Filter": {"Prefix": "builds/"},
                "Transitions": [
                    {
                        "Days": 30,
                        "StorageClass": "STANDARD_IA"
                    },
                    {
                        "Days": 90,
                        "StorageClass": "GLACIER_IR"
                    }
                ],
                "Expiration": {
                    "Days": 365
                }
            },
            {
                "ID": "CleanupOldVersions",
                "Status": "Enabled",
                "Filter": {"Prefix": ""},
                "NoncurrentVersionExpiration": {
                    "NoncurrentDays": 30
                }
            }
        ]
    }'

This does:

  1. After 30 days → move builds to Standard-IA (cheaper)
  2. After 90 days → move to Glacier Instant Retrieval (even cheaper)
  3. After 365 days → delete permanently
  4. Old versions of ALL objects → delete after 30 days

Lifecycle Visualisation

  Day 0          Day 30           Day 90           Day 365
  ──────────────────────────────────────────────────────────►
  │ Standard │──► Standard-IA │──► Glacier IR  │──► Deleted
  │ $0.023/GB│   $0.0125/GB  │   $0.004/GB   │

Common Lifecycle Patterns for DevOps

Object Type Keep in Standard Move to IA Archive/Delete
Build artefacts 7 days 30 days Delete at 90 days
Application logs 14 days 60 days Delete at 180 days
Terraform state Always Never Never (versioned)
Database backups 7 days 30 days Glacier at 90, delete at 365
CloudTrail logs 90 days 180 days Glacier at 365

Quick Reference

Task Command
Enable versioning aws s3api put-bucket-versioning --bucket BUCKET --versioning-configuration Status=Enabled
List versions aws s3api list-object-versions --bucket BUCKET --prefix KEY
Get specific version aws s3api get-object --bucket BUCKET --key KEY --version-id VID FILE
Set lifecycle aws s3api put-bucket-lifecycle-configuration --bucket BUCKET --lifecycle-configuration file://lifecycle.json
Get lifecycle aws s3api get-bucket-lifecycle-configuration --bucket BUCKET

Next → S3 for DevOps Workflows

Updated: