As your Terraform setups grow, managing how and when resources should be created, replaced, or protected becomes just as important as defining them.
Terraform’s lifecycle meta-arguments help you control exactly that.
What Are Lifecycle Meta-Arguments?
Lifecycle meta-arguments tell Terraform how it should behave when creating, updating, or destroying a resource.
create_before_destroy
prevent_destroy
ignore_changes
replace_triggered_by
precondition
postcondition
- create_before_destroy (Zero-Downtime Deployments) By default, Terraform destroys the old resource first and then creates a new one. This can cause downtime for load balancers, Auto Scaling Groups, or any production resource.
create_before_destroy flips the order:
resource "aws_launch_template" "app" {
name_prefix = "app-template-"
image_id = "ami-12345"
instance_type = "t3.micro"
lifecycle {
create_before_destroy = true
}
}
- prevent_destroy (Protect Critical Resources) If you want to ensure Terraform NEVER destroys a resource accidentally:
resource "aws_s3_bucket" "logs" {
bucket = "prod-logs-bucket"
lifecycle {
prevent_destroy = true
}
}
- ignore_changes (Handle External Modifications) Sometimes AWS updates a field automatically or another external process modifies it. Terraform will detect “drift” and try to revert it even if you don’t want that.
resource "aws_instance" "web" {
ami = "ami-12345"
instance_type = "t3.micro"
tags = {
Name = "web-server"
}
lifecycle {
ignore_changes = [
tags["LastUpdatedBy"],
user_data,
]
}
}
- replace_triggered_by (Automatic Resource Replacement) Sometimes you want Terraform to replace a resource only if something else changes.
Example: Replace EC2 instance when Launch Template changes.
resource "aws_instance" "app" {
ami = "ami-12345"
instance_type = "t3.micro"
lifecycle {
replace_triggered_by = [
aws_launch_template.app_latest
]
}
}
- precondition (Validate Before Deployment) Introduced in Terraform 1.x, precondition helps you fail early if input variables don't meet requirements. Example: Validate that the instance size is not too small.
resource "aws_instance" "db" {
ami = "ami-12345"
instance_type = var.db_size
lifecycle {
precondition {
condition = contains(["t3.medium", "t3.large"], var.db_size)
error_message = "Database instance must be at least t3.medium."
}
}
}
- postcondition (Validate After Deployment) This validates the result after creation.
Example: Ensure the S3 bucket actually has versioning enabled:
resource "aws_s3_bucket_versioning" "versioning" {
bucket = aws_s3_bucket.mybucket.id
versioning_configuration {
status = "Enabled"
}
lifecycle {
postcondition {
condition = self.versioning_configuration[0].status == "Enabled"
error_message = "Versioning must remain enabled on the bucket."
}
}
}
Video: https://youtu.be/60tOSwpvldY?si=UrpTR6YYhV2DiWPG
Conclusion:
Lifecycle meta-arguments give you fine-grained control over how Terraform behaves, reducing downtime, preventing accidents, and ensuring compliance.
Top comments (0)