Terraform Lifecycle — Because “Destroy Everything” Isn’t Always the Best Plan

Introduction

Ever applied a Terraform plan and suddenly watched it destroy and recreate a perfectly working resource? 😅
That was me — until I discovered the power of Terraform lifecycle blocks.

If you’ve been working with Terraform for a while, you already know how declarative and powerful it is. But sometimes, Terraform’s default behavior can be… a bit too eager. That’s where lifecycle rules come in — to give you control over how Terraform creates, updates, and destroys your infrastructure resources.


🧠 What Is a Lifecycle Block?

A lifecycle block in Terraform allows you to tweak the default behavior of resource management.

You can think of it as Terraform’s etiquette manual — it helps Terraform know when to act, what to skip, and what not to touch.

Here’s what it looks like:

resource "aws_instance" "web" {
  ami           = "ami-123456"
  instance_type = "t2.micro"

  lifecycle {
    prevent_destroy      = true
    create_before_destroy = true
    ignore_changes       = [tags]
  }
}

⚙️ Lifecycle Arguments Explained

1. prevent_destroy

If you’ve ever accidentally destroyed a production resource, this one’s your new best friend.

lifecycle {
  prevent_destroy = true
}

Terraform will refuse to destroy this resource — unless you manually remove the flag. It’s your safety net against “oops” moments.

💡 Best used for databases, critical load balancers, and persistent storage.


2. create_before_destroy

This one ensures zero downtime during replacements. Terraform will first create the new resource before destroying the old one.

lifecycle {
  create_before_destroy = true
}

It’s extremely useful when dealing with resources like EC2 instances, load balancers, or anything in a production chain that needs to stay online.

🚀 Think of it as blue-green deployment, but for Terraform resources.


3. ignore_changes

Sometimes Terraform shows a diff for changes that don’t matter — like automatically assigned IPs or tags added by cloud providers.

lifecycle {
  ignore_changes = [tags, private_ip]
}

Terraform will simply ignore these attributes during plan/apply.

🧩 Perfect when using autoscaling groups, managed services, or provider-added metadata.


💡 Why Use Lifecycle?

Because not all changes should be destructive.
Terraform lifecycle gives you the control to:

✅ Prevent accidental data loss
✅ Maintain zero downtime rollouts
✅ Keep your plans clean from unnecessary updates
✅ Align Terraform with real-world infra patterns

It’s not about changing Terraform’s nature — it’s about teaching it manners. 😄


⚠️ Things to Keep in Mind

  • prevent_destroy can block legitimate deletions — use it wisely.
  • Misusing ignore_changes may cause drift between your code and real infrastructure.
  • create_before_destroy doesn’t work if the provider doesn’t allow two resources with the same name/ID.

🚀 Conclusion

Terraform lifecycle blocks are one of those underrated features that can save you hours of debugging, unplanned downtime, and heart-stopping “why did this get deleted?” moments.

Once you start using them wisely, your infrastructure becomes more predictable — and Terraform becomes less of a rebel. 😉