Explain the `lifecycle` meta-argument: `create_before_destroy`, `prevent_destroy`, and `ignore_changes`.

5 minintermediateterraformlifecyclemeta-arguments

Quick Answer

`lifecycle` is a nested block on any resource that overrides Terraform's default replace behavior. `create_before_destroy = true` provisions the replacement resource *before* destroying the old one (essential for things like launch configurations or DNS records where a gap in availability matters). `prevent_destroy = true` makes `terraform destroy`/a plan that would delete the resource fail outright, guarding critical resources like production databases from accidental deletion. `ignore_changes = [tags]` tells Terraform to stop reporting/reconciling drift on specific attributes, useful when another process (autoscaling, a tagging automation) legitimately manages that field.

Detailed Answer

The lifecycle block is a nested meta-argument available on any resource that overrides Terraform's default behavior for how it handles replacement, deletion, and drift on specific attributes.

create_before_destroy

resource "aws_launch_configuration" "app" {
  name_prefix   = "app-"
  image_id      = var.ami_id
  instance_type = "t3.micro"

  lifecycle {
    create_before_destroy = true
  }
}

By default, when a resource must be replaced (a ForceNew attribute changed), Terraform destroys the old one first, then creates the new one. For resources where a gap in availability matters — a launch configuration referenced by an auto-scaling group, a DNS record, a load balancer target — that ordering can cause an outage. create_before_destroy = true flips the order: create the replacement first, then destroy the old one, so there's overlap instead of a gap. (Note: this often requires the resource's name to not collide, hence name_prefix instead of a fixed name above.)

prevent_destroy

resource "aws_db_instance" "prod" {
  # ...
  lifecycle {
    prevent_destroy = true
  }
}

Makes any plan that would destroy this resource — including via terraform destroy, removing the resource block, or a count/for_each change that would eliminate this instance — fail outright with an error, rather than actually destroying it. A guardrail for irreplaceable resources like production databases, where an accidental destroy would be catastrophic.

ignore_changes

resource "aws_instance" "web" {
  # ...
  lifecycle {
    ignore_changes = [tags, ami]
  }
}

Tells Terraform to stop reporting (and stop trying to reconcile) drift on the listed attributes. Useful when something else legitimately manages that field outside of Terraform — e.g., an autoscaling process that updates desired_capacity, or a tagging-automation Lambda that adds cost-allocation tags Terraform doesn't know about. Without ignore_changes, every plan would show a spurious diff trying to revert that external change.

Interview-ready summary

All three are ways of telling Terraform "don't apply your default replace/destroy/drift-correction behavior here" — used for availability (create_before_destroy), safety (prevent_destroy), and coexistence with external processes (ignore_changes).

Related Resources