OpenTofu: A Beginners Guide to a Terraform Fork Including Migration From Terraform
Working with OpenTofu
LifeCycle Rules
In this lesson, we’ll dive into OpenTofu’s lifecycle rules to control how resources are created, updated, or destroyed. Proper use of these rules helps you avoid downtime, accidental deletions, and unnecessary modifications.
Table of Contents
- Default Behavior
- create_before_destroy
- prevent_destroy
- ignore_changes
- Summary of Lifecycle Rules
- Further Reading
Default Behavior
By default, OpenTofu will destroy and then recreate any resource if a change requires replacement (for example, updating an AMI in an aws_instance
).
resource "aws_instance" "cerberus" {
ami = "ami-2158c0f087598787a"
instance_type = "m5.large"
tags = {
Name = "Cerberus-Webserver"
}
}
After changing the ami
value and running tofu apply
, you’ll see:
$ tofu apply
...
Plan: 1 to add, 0 to change, 1 to destroy.
...
aws_instance.cerberus: Destroying... [id=i-0abcd1234efgh567a]
aws_instance.cerberus: Creation complete after 1m2s [id=i-1wxyz9876uvgh5432]
Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
1. create_before_destroy
Use create_before_destroy = true
to provision the replacement resource before tearing down the old one. This helps minimize downtime.
resource "aws_instance" "cerberus" {
ami = "ami-2158c0f087598787a"
instance_type = "m5.large"
tags = {
Name = "Cerberus-Webserver"
}
lifecycle {
create_before_destroy = true
}
}
Running tofu apply
now provisions the new instance first:
$ tofu apply
...
Plan: 1 to add, 0 to change, 1 to destroy.
...
aws_instance.cerberus: Creating...
aws_instance.cerberus: Creation complete after 1m1s [id=i-9abcd1234mnop678]
aws_instance.cerberus: Destroying... [id=i-0abcd1234efgh567a]
Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
2. prevent_destroy
Set prevent_destroy = true
to block any accidental deletion during an apply
. OpenTofu will throw an error if a change requires replacement.
resource "aws_instance" "cerberus" {
ami = "ami-2158c0f087598787a"
instance_type = "m5.large"
tags = {
Name = "Cerberus-Webserver"
}
lifecycle {
prevent_destroy = true
}
}
If you change the AMI and run tofu apply
, you’ll get:
$ tofu apply
Error: Instance aws_instance.cerberus must be replaced
on main.tf line 2, in resource "aws_instance" "cerberus":
2: resource "aws_instance" "cerberus" {
Resource aws_instance.cerberus has lifecycle prevent_destroy set, but plan requires resource to be replaced. This operation would destroy the existing resource.
Note
prevent_destroy
does not block a direct tofu destroy
. It only prevents destruction during apply operations triggered by configuration changes.
3. ignore_changes
The ignore_changes
meta-argument instructs OpenTofu to skip tracking specified attributes, even if they drift from your configuration.
resource "aws_instance" "cerberus" {
ami = "ami-2158c0f087598787a"
instance_type = "m5.large"
tags = {
Name = "Cerberus-Webserver-1"
}
lifecycle {
ignore_changes = [
tags
]
}
}
If someone updates the Name
tag manually in the AWS console, tofu apply
reports no changes:
$ tofu apply
aws_instance.cerberus: Refreshing state... [id=i-1234567890abcdef0]
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
You can ignore multiple attributes, or even all changes:
resource "aws_instance" "cerberus" {
ami = "ami-2158c0f087598787a"
instance_type = "m5.large"
tags = {
Name = "Cerberus-Webserver-2"
}
lifecycle {
ignore_changes = all
}
}
$ tofu apply
aws_instance.cerberus: Refreshing state... [id=i-1234567890abcdef0]
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Warning
Use ignore_changes = all
cautiously. Ignoring all drift may mask unintended configuration drift over time.
Summary of Lifecycle Rules
Rule | Description | Example |
---|---|---|
create_before_destroy | Provision the new resource before destroying the old to minimize downtime. | create_before_destroy = true |
prevent_destroy | Block any destructive change during apply , protecting critical resources. | prevent_destroy = true |
ignore_changes | Skip specific attribute changes or all drift between config and real-world state. | ignore_changes = [tags] or all |
Default (no lifecycle) | Replace resources by destroying then recreating whenever a change requires resource replacement. | N/A |
Further Reading
Watch Video
Watch video content