DEV Community

Rajesh Mishra
Rajesh Mishra

Posted on Originally published at howtostartprogramming.in

Terraform AWS S3 bucket with versioning and lifecycle rules — Complete Guide

Terraform AWS S3 bucket with versioning and lifecycle rules — Complete Guide

A practical, in-depth guide to Terraform AWS S3 bucket with versioning and lifecycle rules with examples.

INTRO

Every production workload that stores files, logs, or backups in Amazon S3 eventually runs into two hard‑to‑ignore problems: uncontrolled storage growth and accidental data loss. Without versioning, a single rm or an overwritten object can wipe out critical information forever. Without lifecycle policies, old objects sit in a bucket forever, inflating your bill and making compliance audits a nightmare.

Terraform makes it easy to codify the “guardrails” you need, but the syntax for versioning and lifecycle rules is surprisingly terse. A small mistake—like forgetting to set force_destroy on a bucket with versioning enabled—can lock you out of a clean destroy. The full guide walks you through the exact Terraform blocks you need, explains the gotchas, and shows how to keep your S3 costs predictable while preserving every version of your data.

WHAT YOU'LL LEARN

  • How to enable versioning on an S3 bucket using Terraform and why you should always pair it with a proper lifecycle configuration.
  • The difference between transition and expiration actions, and how to chain them to move old data to Glacier or delete it after a retention period.
  • How to write lifecycle rules that target specific prefixes or tags, letting you treat logs, backups, and user uploads differently.
  • The pitfalls of force_destroy with versioned buckets and the safest ways to destroy resources in CI pipelines.
  • Real‑world examples of cost‑optimization: moving non‑current versions to cheaper storage classes after 30 days, then purging after 365 days.
  • Tips for testing your bucket configuration locally with terraform plan and validating policies with AWS IAM Access Analyzer.

A SHORT CODE SNIPPET

resource "aws_s3_bucket" "logs" {
bucket = "my-app-logs"
versioning {
enabled = true
}

lifecycle_rule {
id = "log-retention"
enabled = true

filter {
prefix = "2024/"
}

transition {
days = 30
storage_class = "GLACIER"
}

expiration {
days = 365
}

noncurrent_version_transition {
days = 60
storage_class = "GLACIER"
}

noncurrent_version_expiration {
days = 730
}
}

force_destroy = false
}
Enter fullscreen mode Exit fullscreen mode

This snippet shows the essential pieces: versioning, a rule that moves objects older than 30 days to Glacier, and a separate rule that expires non‑current versions after two years.

KEY TAKEAWAYS

  • Versioning is a safety net, not a cost sink—pair it with lifecycle rules to keep storage bills in check.
  • Lifecycle filters let you apply different policies to subsets of objects, giving you fine‑grained control without multiple buckets.
  • Never set force_destroy = true on a versioned bucket in production; use a dedicated destroy script that first removes all object versions.
  • Testing and iteration are crucial—run terraform plan after each rule change and validate the resulting bucket policy with AWS tools.

👉 Read the complete guide with step-by-step examples, common mistakes, and production tips:

Terraform AWS S3 bucket with versioning and lifecycle rules — Complete Guide

Top comments (0)