Terraform & IaC

Control How Resources Live & Die: Resource Lifecycle

Lesson 12 of 14 · 9 min · Advanced

By default, when an argument change forces a resource replacement, Terraform destroys the old resource first and creates the new one — causing service downtime. The lifecycle meta-argument gives you fine-grained control to prevent accidental deletions, enable zero-downtime updates, and ignore external drift.

The Default Lifecycle & The Downtime Gap

When you change an immutable attribute on a cloud resource (like changing an EC2 instance's AMI, or recreating a security group), Terraform must replace the resource. Terraform's default sequence is Destroy Old → Create New.

Default Sequence (Downtime Gap)

  • 1. Terminate Live Server
  • →
  • 2. Service Outage Gap (3-5 min)
  • →
  • 3. New Server Boots

The lifecycle {} Block

Placed directly inside any resource block to customize how Terraform plans and applies operations against that specific cloud asset.

1. create_before_destroy = true

main.tf
resource "aws_instance" "web" {
  ami           = "ami-0123456789abcdef0"
  instance_type = "t3.micro"

  lifecycle {
    create_before_destroy = true
  }
}

Reverses the Creation Order

Terraform provisions the new resource first. Once the new resource is verified active and running, Terraform deletes the old one. This ensures zero downtime during web server and load balancer rolling replacements.

2. prevent_destroy = true (Accident Guardrail)

rds.tf
resource "aws_db_instance" "production_db" {
  allocated_storage = 100
  engine            = "postgres"
  instance_class    = "db.t3.large"
  db_name           = "production_data"

  lifecycle {
    prevent_destroy = true
  }
}

Aborts Execution Plan Immediately

If anyone accidentally runs terraform destroy or edits a setting that requires database recreation, Terraform fails the plan step instantly with an error:

Error: Instance cannot be destroyed by Terraform
Resource has lifecycle.prevent_destroy set.

3. ignore_changes: Stop Fighting External Tools

asg.tf
resource "aws_autoscaling_group" "app_asg" {
  name             = "app-autoscaling"
  min_size         = 2
  max_size         = 10
  desired_capacity = 2

  lifecycle {
    # Ignore changes made by AWS Auto Scaling policies
    ignore_changes = [
      desired_capacity,
      tags
    ]
  }
}

Why ignore_changes is Essential

During peak shopping hours, AWS Auto Scaling increases desired_capacity from 2 to 8. Without ignore_changes, running Terraform would see drift and force capacity back down to 2, causing an outage.

4. depends_on: Explicit Dependency Hints

s3_iam.tf
resource "aws_iam_role_policy_attachment" "s3_access" {
  role       = aws_iam_role.app.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
}

resource "aws_instance" "worker" {
  ami                  = "ami-0123456789abcdef0"
  instance_type        = "t3.micro"
  iam_instance_profile = aws_iam_instance_profile.app.name

  # Wait until IAM policy is attached before booting
  depends_on = [
    aws_iam_role_policy_attachment.s3_access
  ]
}

When Terraform Needs a Hint

Normally Terraform infers dependencies implicitly by inspecting variable references (e.g. subnet_id = aws_subnet.web.id). When two resources have a hidden timing dependency that isn't referenced directly in arguments, use depends_on.

Lifecycle Arguments Reference

ArgumentValue TypeCore Purpose
create_before_destroyboolCreate replacement before terminating original (zero downtime).
prevent_destroyboolBlock destruction of critical databases or storage.
ignore_changeslist(attribute) or allPrevent Terraform from overwriting changes made by external systems.
replace_triggered_bylist(reference)Force recreation when an associated resource or configuration hash changes.
depends_onlist(resource)Enforce explicit DAG creation order before provisioning.