OpenTofu 1.12.0 Brings Dynamic prevent_destroy and Provider Checksum Fixes

   |   3 minute read   |   Using 606 words

OpenTofu 1.12.0 landed on May 14, 2026, and it pulls a few sharp edges out of day to day usage. The headline items: prevent_destroy can now reference variables, the provider registry ships complete checksums, and a new -json-into=FILENAME flag lets you keep JSON output alongside the normal terminal UI.

The full release notes are on the GitHub release page. The maintainers also published a companion blog post with longer write ups of each change.

Lifecycle changes that affect real workflows

Two updates here matter for anyone juggling stateful resources.

Dynamic prevent_destroy is the bigger one. Before this release, prevent_destroy had to be a static literal in the lifecycle block. You could not toggle it from a variable, which made shared modules awkward to use across environments. From v1.12.0 onwards it accepts any expression available in the module, including variables:

variable "prevent_destroy_database" {
  type    = bool
  default = true
}

resource "example_database" "example" {
  lifecycle {
    prevent_destroy = var.prevent_destroy_database
  }
}

The other addition is the new destroy = false lifecycle meta argument. With it set, removing the resource from configuration drops the object from state without first calling destroy on the remote object. That replaces a common dance of tofu state rm followed by editing the configuration to remove the resource block.

Provider checksums stop tripping over caches and mirrors

If you run OpenTofu with a shared plugin cache directory or against an internal mirror, you probably hit the case where the lock file was missing the right checksum format. The fix was to run tofu providers lock and then commit the updated file. Annoying, easy to forget, and a frequent source of CI failures.

In v1.12 the OpenTofu Registry now serves the full set of checksum formats for every provider, so a plain tofu init produces a lock file that already covers the global plugin cache and verifies packages from a local mirror. No extra step required.

This is the kind of fix that is invisible until you stop having to think about it.

JSON output without losing the human UI

Several OpenTofu commands have two output modes: a normal terminal UI and a machine readable JSON payload via -json. Until now you picked one or the other, which forced wrapper tools to reimplement the entire interactive UI in their own renderer before they were actually usable.

The new -json-into=FILENAME option writes the same payload that -json would, but to a file. Standard output keeps the normal interactive UI. Tools that consume the JSON can now act as a supplement to the OpenTofu UI rather than a replacement for it.

Upgrade notes

A handful of items will bite if you skip them.

  • connection { type = "winrm" } now emits a deprecation warning. WinRM is scheduled for removal in the v1.13 series. The recommended replacement is OpenSSH for Windows.
  • 32 bit CPU builds (386 and arm) are on a deprecation path. v1.12 does not warn yet, but v1.13 is expected to start warning, and the official packages will be dropped in a later release. 64 bit (amd64 and arm64) is unaffected.
  • macOS 12 Monterey is now the minimum supported macOS version.
  • The OPENTOFU_USER_AGENT environment variable has been removed. If you used it to override the User Agent header on HTTP requests, you will need a different approach.
  • On Unix systems OpenTofu now reads the BROWSER environment variable when it needs to open a web browser. If you already have BROWSER set in your shell for unrelated reasons, OpenTofu may now open a browser differently than before. Unset it to restore the old platform behavior.

Where to get it



denis256 at denis256.dev