OpenTofu 1.12 shipped May 14 with the feature Terraform users have been requesting since 2016: a prevent_destroy lifecycle setting that accepts variables. Terraform opened issue #30957 nearly a decade ago and never resolved it. OpenTofu closed the equivalent in this release. That is the headline, and it has real consequences for every platform engineer managing multi-environment infrastructure stacks.
Dynamic prevent_destroy: The Decade-Long Wait Is Over
If you have ever managed infrastructure across development and production environments using Terraform, you have hit this wall. The prevent_destroy lifecycle meta-argument accepts only hard-coded booleans — you cannot pass a variable, you cannot reference a local value. A module that protects a production database from accidental deletion cannot be the same module you use in dev, because in dev you need to tear things down freely.
The result was predictable: forked modules, duplicate configurations, and tribal knowledge about which module tree was “the prod one.” Some teams maintained environment-specific module directories. Others skipped prevent_destroy entirely and hoped for the best. OpenTofu 1.12 ends that. The lifecycle block can now reference any expression within the same module scope:
variable "is_production" {
type = bool
default = false
}
resource "aws_db_instance" "main" {
lifecycle {
prevent_destroy = var.is_production
}
}
Set is_production = true in your production workspace. Leave it false everywhere else. One module, all environments. This is the kind of fix that looks small in a changelog but eliminates an entire category of infrastructure footgun. The full release notes are on the official OpenTofu blog.
Declarative State Removal with destroy = false
OpenTofu 1.12 also introduces a new destroy lifecycle meta-argument. When set to false, OpenTofu removes the resource from its state without calling the provider to destroy the underlying object — the declarative replacement for the manual tofu state rm workflow:
resource "aws_s3_bucket" "legacy" {
bucket = "my-legacy-data"
lifecycle {
destroy = false
}
}
The practical uses are narrow but important: stopping management of a resource without deleting it, or handing infrastructure off to another team or tool. Previously this required CLI incantations and a Slack message explaining what you did. Now it is in the config where it belongs.
Faster tofu init, Less Lock File Pain
Two smaller changes in 1.12 add up to a noticeably better experience on projects with many providers. Provider packages are now downloaded concurrently during tofu init — if you are pulling in ten or fifteen providers, you will feel the difference. Additionally, tofu init now auto-populates both zh: and h1: hash formats in the lock file in a single pass. Previously, cross-platform CI pipelines required a separate tofu providers lock step to pre-populate all platform hashes. That step is gone. The first tofu init after upgrading will update your lock file — commit those changes, they are expected and intentional.
The release also adds a -json-into=FILENAME flag to any command that supports JSON output. It writes machine-readable output to a file while keeping human-readable terminal output intact — a clean fix for teams that pipe plan output into scripts without sacrificing readability. According to InfoQ’s analysis, this release represents OpenTofu’s clearest statement yet that it is building its own product roadmap, not just maintaining Terraform parity.
Why This Release Matters Beyond the Features
OpenTofu sits at roughly 12% adoption among IaC practitioners, with 27% of teams planning to evaluate or expand its use. The IBM acquisition of HashiCorp in December 2024 has kept licensing uncertainty alive for enterprises on Terraform. But the more interesting story is what 1.12 demonstrates about OpenTofu’s trajectory: it is no longer just a parity fork. State encryption shipped in 1.7 — Terraform still does not have it. Dynamic prevent_destroy ships in 1.12 — Terraform’s decade-old issue sits unresolved. These are deliberate product decisions that Terraform declined to make. The fork has opinions now, and they are shipping.
How to Upgrade to OpenTofu 1.12
If you are using tofuenv:
tofuenv install 1.12.0
tofuenv use 1.12.0
On macOS with Homebrew: brew upgrade opentofu. After upgrading, run tofu init and commit the updated lock file, then run tofu plan to verify nothing unexpected changed. For additional context on what this release means for the IaC ecosystem, env0’s breakdown is worth reading.













