Explain the `lifecycle` meta-argument: `create_before_destroy`, `prevent_destroy`, and `ignore_changes`.
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).