Article · part of a guide
Understanding the Terraform ignore_changes Lifecycle Block
Learn how and when to use the ignore_changes life cycle block.

Key takeaways
- The ignore_changes argument in Terraform's lifecycle block tells Terraform not to plan updates for specific attributes even when state no longer matches the HCL.
- It is most useful for computed defaults set by the provider, attributes modified by external systems, and temporarily suppressing false positives during module refactors.
- Prefer ignore_changes = [tags_all] over [tags] to ignore all tag changes, and reserve the special keyword all for resources managed entirely by another system.
- ignore_changes only suppresses plan output for attributes you anticipate; if you also edit such an attribute in HCL, that change is ignored until you remove it from the list.
- Tolerated drift is still drift, so detecting unexpected drift across many resources is a separate problem handled by a platform with continuous drift detection like Scalr.
The lifecycle block changes how Terraform handles a resource, overriding its normal behavior. One of its arguments, ignore_changes, helps when something outside your Terraform code modifies a resource and you don't want Terraform to undo that change on the next run. It works the same on OpenTofu.
Put simply, ignore_changes tells Terraform: "When you run a plan, don't consider changes to these specific attributes, even if the state value no longer matches the HCL value."
What Problem Does ignore_changes Solve?
Terraform's job is to keep the actual state of your infrastructure matching the desired state you defined in your HCL code. When the two don't match, Terraform plans an update to correct the drift.
ignore_changes earns its keep in three common cases where that drift is harmless or intentional:
- Computed defaults. The provider sets an attribute after creation that you never declared, like a default security policy or a generated ID. Without
ignore_changes, every plan tries to reset it. - External modifications. Another system or a person changes one attribute outside Terraform, a tag or a database setting, and you want Terraform to keep managing the resource but leave that attribute alone.
- Imports and refactors. Freshly imported or refactored resources throw false positives.
ignore_changessuppresses them while you bring the HCL into line, without risking a destructiveapplyin the meantime.
How to Use the ignore_changes Block
The lifecycle block is placed inside a resource block. The ignore_changes argument accepts a list of attribute names that should be excluded from drift detection.
Syntax
resource "resource_type" "resource_name" {
# Standard resource configuration...
lifecycle {
# Provide a list of attribute names to ignore.
ignore_changes = [
attribute_one,
attribute_two,
# You can also use the special keyword 'all'
# all,
]
}
}
Example: Ignoring Tags and Network Rules
Say you have an AWS EC2 instance. You want Terraform to manage its type and AMI, but you let your monitoring team update certain tags, and a separate tool manages the user data script once the instance is running.
resource "aws_instance" "web_server" {
ami = "ami-0abcdef1234567890"
instance_type = "t2.micro"
# Standard tags managed by Terraform
tags = {
Project = "MyWebApp"
Owner = "Team Alpha"
}
lifecycle {
# Ignore tags_all, allowing external automation to add/remove tags without
# triggering a plan difference for this resource.
# Also ignore 'user_data' if a bootstrap tool modifies it post-launch.
ignore_changes = [
tags_all,
user_data,
]
}
}
tags vs tags_all, all, and the HCL-edit trap
The tags vs. tags_all Dilemma
Most cloud providers have a tags argument (explicitly managed) and a tags_all argument (the complete set of tags, including provider-default tags).
- If you use
ignore_changes = [tags], Terraform will ignore only the tags you explicitly defined. This is rarely what you want. - If you use
ignore_changes = [tags_all], Terraform ignores all tag changes on the resource. This is often the safest choice if you want to allow external tag management, but it means Terraform can never enforce a specific tag set.
Using all
The special keyword all ignores changes to every attribute on the resource.
lifecycle {
ignore_changes = all
}
This stops all drift, but it also makes the resource read-only as far as Terraform is concerned. Any change you make to that resource's block in HCL (say, changing instance_type from t2.micro to t2.medium) gets ignored. Use all only when another system manages the resource entirely and you just need Terraform to keep it from being destroyed by accident.
State-Only vs. Configuration-Based Changes
ignore_changes works by comparing the current state (what Terraform read from the cloud) against the configuration (what is written in your HCL). It only suppresses the plan output; the actual change still exists in the cloud.
If you change an attribute in your HCL but also have ignore_changes set for it, Terraform ignores your HCL change on the next apply. To make the change stick, remove the attribute from the ignore_changes list, run apply, and then add it back if you want.
Using ignore_changes with Drift
Every entry in an ignore_changes list is drift you've decided to live with. That's fine for a tag the monitoring team owns or a user_data script a bootstrap tool rewrites. It stops being fine when the list keeps growing, because at that point you're not tolerating one known change, you're switching off Terraform's ability to notice unknown ones. Detecting and remediating unexpected drift across hundreds of resources and workspaces is a separate problem, and one of the main reasons teams adopt a dedicated Terraform automation platform with continuous drift detection built in.
Most ignore_changes blocks exist to tolerate out-of-band edits, and tolerated drift is still drift. If the list of ignored attributes keeps growing, schedule drift detection rather than widening it further: our drift detection guide covers the workflow, and Scalr runs scheduled drift checks across workspaces, free up to 50 runs per month, with drift-detection runs not counted against that allowance.
This blog has been verified for Terraform and OpenTofu
About the author

director of platform engineering at Scalr
Ryan Fee is the director of platform engineering at Scalr, with over 15 years of experience improving infrastructure experiences at companies large and small.
Part of this guide
9 sheets