# terraform / lifecycle / guardrails
Control How Resources Live & Die: Resource Lifecycle
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)
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
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)
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
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
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
| Argument | Value Type | Core Purpose |
|---|---|---|
create_before_destroy | bool | Create replacement before terminating original (zero downtime). |
prevent_destroy | bool | Block destruction of critical databases or storage. |
ignore_changes | list(attribute) or all | Prevent Terraform from overwriting changes made by external systems. |
replace_triggered_by | list(reference) | Force recreation when an associated resource or configuration hash changes. |
depends_on | list(resource) | Enforce explicit DAG creation order before provisioning. |