How it works
The explanation, with examples you can run.
create_before_destroy
resource "random_pet" "name" { prefix = var.env lifecycle { create_before_destroy = true }}With this setting, changing prefix produced (Terraform 1.5.7):
+/- create replacement and then destroy # random_pet.name must be replaced+/- resource "random_pet" "name" { ~ prefix = "dev" -> "prod" # forces replacement+/- instead of -/+. Use it for anything serving traffic (instances, launch templates, certificates). The new and old objects must be able to exist together, so avoid fixed names (use name_prefix where the provider offers it). The setting also propagates to the resources this one depends on.
prevent_destroy
lifecycle { prevent_destroy = true}Any plan that would destroy the resource, including a replacement, fails:
Error: Instance cannot be destroyed on main.tf line 14: 14: resource "random_pet" "name" { Resource random_pet.name has lifecycle.prevent_destroy set, but the plancalls for this resource to be destroyed. To avoid this error and continuewith the plan, either disable lifecycle.prevent_destroy or reduce the scopeof the plan using the -target flag.It protects state buckets, databases and DNS zones from a careless change. It does not survive deleting the block (the protection lives in configuration), so pair it with the provider's own deletion protection where one exists.
ignore_changes
lifecycle { ignore_changes = [desired_count, tags["LastScannedBy"]]}Terraform sets these on create and then leaves them alone. Use it for values another system owns (an autoscaler, a tagging tool). Avoid ignore_changes = all, which hides real drift.
Replacing on purpose
terraform apply -replace=aws_instance.apprebuilds one object that is degraded but whose configuration is unchanged. It replaces the deprecatedterraform taint.replace_triggered_byrebuilds a resource when another changes. With the built-interraform_dataresource as a trigger (Terraform 1.16.6):
resource "terraform_data" "release" { input = var.release} resource "random_id" "cache_key" { byte_length = 4 lifecycle { replace_triggered_by = [terraform_data.release] }} # random_id.cache_key will be replaced due to changes in replace_triggered_by-/+ resource "random_id" "cache_key" { # terraform_data.release will be updated in-place ~ resource "terraform_data" "release" { ~ input = "v1" -> "v2" Plan: 1 to add, 1 to change, 1 to destroy.Preconditions and postconditions
lifecycle also takes precondition and postcondition blocks: assertions checked during plan or after apply, such as "the AMI must be arm64" or "the bucket must have versioning". They turn assumptions into errors with clear messages, before a wrong value reaches production.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.