Skip to main content

OpenTofu v1.13.0

We've just published OpenTofu v1.13.0!

We intentionally shortened the development period for v1.13.0 so that we're now more closely aligned with the Go release cycle, which means that we maximize the length of time this series can remain under security support: this series will be supported until August 2027.

However, that means that this is a relatively light release in terms of new features. The following are some highlights from the new release:

There are also some important changes to existing behavior that may be relevant to you:

For full details on the changes in this release, refer to the OpenTofu v1.13.0 release notes.

Windows on ARM64 is now a supported platform

Starting with OpenTofu v1.13.0 we are now offering official packages targeting Windows on the ARM64 (also known as "aarch64") CPU architecture.

This has admittedly been a long time coming, and took a while both because we lacked infrastructure for routinely testing on this platform and because we needed to wait for provider plugin support to be established before such releases would be useful.

Most of OpenTofu's builds of the various major cloud platform providers have windows_arm64-targeted packages available, but note that maintainers of third-party providers in OpenTofu Registry set their own policy for which platforms to support and so you may need to upgrade to a new version of a provider you've previously used, and some providers may not yet support this platform at all.

Reducing unknowns during planning

OpenTofu's core workflow relies on predicting as close as possible what will happen during the apply phase so that it can present you with a set of proposed changes during the planning phase. In practice though, various values cannot be completely predicted during the planning phase, and so OpenTofu uses the concept of "unknown values" -- which appear as (known after apply) in the plan output -- to resolve as much as possible while also being clear about what it doesn't know yet.

Unfortunately there are a number of situations where unknown values are inconvenient or can even block progress. There are several OpenTofu features that currently reject values that are not known during the planning phase, such as the enabled, for_each, and count meta-arguments. Separately, some teams run the machine-readable form of the plan output through automatic policy-checking software which is effectively blinded by unknown values and therefore faces a difficult decision between either optimistically allowing it (with the risk that the final values will violate policy) or conservatively blocking it (risking that it'll block changes that would actually have conformed to the policy).

To offer a new form of compromise, OpenTofu v1.13 introduces a number of new functions that are all intended to allow module authors to give OpenTofu additional hints about what they know to be true even though OpenTofu cannot infer it automatically:

  • convert allows you to hint to OpenTofu what type of result is expected, in situations where that's not predictable.

    For example, passing an unknown string to jsondecode usually causes an unknown result of an unknown type, but you may actually know what shape the JSON is expected to be and so could specify it so downstream expressions can rely on that additional information:

    Code Block
    output "example" {
    value = convert(jsondecode(something_dynamic.example.output_json), object({
    id = string
    tags = map(string)
    }))
    }

    If something_dynamic.example.output_json is unknown during planning then the result is still an unknown value, but it's at least an unknown value where OpenTofu knows that accessing the id attribute would produce a string, etc.

  • The assume... family of functions allow you to give hints about the value itself, such as declaring that it will definitely not be null or that it is a string which definitely has a specific prefix.

    For example, it's a common annoyance that most resource types in the hashicorp/aws provider return an unknown id attribute when planning the creation of a remote object, which means that comparing that attribute to null or to the empty string produces an unknown value, which makes it harder to use the result with another module which uses the nullness of an input variable to decide whether to enable something.

    Code Block
    output "vpc_id" {
    value = assumenotnull(
    assumestringprefix(
    aws_vpc.example.id,
    "vpc-",
    )
    )
    }

    Any expression which compares this output value to null or to "" will therefore be able to produce a known false instead of an unknown boolean result. If this value were passed to a module that has a validation rule where the given VPC ID is required to have the prefix vpc- then that would be validated during the plan phase instead of the apply phase so you can get feedback about mistakes sooner.

All of this comes with a significant requirement, though: the module author must be sure that whatever hint they are offering will actually be true during the apply phase. If you promise OpenTofu that an unknown string will have the prefix vpc- and it ends up having the prefix subnet- then the assumestringprefix call will fail during the apply phase. But in situations where the provider documentation or underlying vendor API documentation guarantees something, this can be a good way to let users of your module rely on that guarantee even when the provider itself doesn't provide the relevant hints itself, thereby keeping the workaround for the imprecise plan encapsulated in a shared module.

Linting Experiment

OpenTofu v1.13 includes some very early work towards built-in "linting" features in OpenTofu, although we are hoping to eventually incorporate other similar needs such as policy enforcement into a single comprehensive feature.

For this first release we've just got some of the internal infrastructure for representing which lint rules are enabled and for reporting lint results back to the operator as warnings. There are some initial built-in rules relating to features of the OpenTofu language included as examples.

You can find out more about what we're hoping to achieve with this set of features in future releases, and about the initial experimental functionality included in v1.13.0, in our separate blog post: A Vision for Built-in Linting. If you are interested in built-in linting and policy features, we'd love to hear your feedback! There's more information in the other blog post about how you could contribute.

Symbol Libraries Experiment

A common frustration from OpenTofu configuration authors is that there are various pieces of shared data or functionality that they'd like to share across many modules and many configurations, but OpenTofu's main unit of reuse -- shared modules -- is designed for sharing definitions of stateful resources, not for sharing arbitrary data and logic.

In answer to that frustration we're considering a new kind of artifact called a "Symbol Library", which is a reusable collection of values, functions, and type aliases that can be imported from all of the same source types that are already supported for modules.

For example, you could write a symbol library representing a cross-cutting representation of DNS records and your organization's conventions for using them, which you could then import from multiple different modules to help ensure that they all "talk the same language" when integrated together into your overall configuration.

Code Block
typedef "recordset" {
type = set({
name = string
type = string
ttl = number
records = set(string)
})
}

function "a_records" {
type = symbols::dns_recordset() # refers to the typedef just above

parameter "records" {
type = map(set(string))
}

parameter "ttl" {
type = number
}

return = [
for name, ip_addrs in param.records : {
name = name
type = "A"
ttl = param.ttl
records = ip_addrs
}
]
}

The specific language elements used here are just a starting point which we expect to continue evolving based on your feedback. You can find out more about this experiment in our separate blog post: An Introduction to OpenTofu Symbol Libraries.

If you're interested in this feature -- and especially if you try out the experimental form of it during the v1.13 series -- then we'd love to hear your feedback! There's more information in the other blog post about how you could contribute.

base64gzip implementation changes

OpenTofu is written in the Go programming language and offers a built-in function base64gzip which is implemented in terms of a gzip implementation in the Go standard library.

The upstream implementation of this function was changed in a way that causes it to now produce results that are equivalent but not byte-for-byte identical to previous versions. Therefore if you've used base64gzip in the definition of a resource argument in your configuration OpenTofu may indicate that the argument needs to change after you upgrade to OpenTofu v1.13.0 or later.

If you're using base64gzip in a context where you cannot immediately accept that change, we recommend temporarily using the ignore_changes meta-argument to tell OpenTofu to retain the previous value for now. You can remove that argument again once you're ready to change to the new gzip result.

As an alternative temporary workaround, an OpenTofu provider compiled with Go v1.26 or earlier could provide equivalent functions based on the previous implementation. The OpenTofu project does not have an official provider for this purpose, but third-party providers may be published in OpenTofu Registry.

WinRM is no longer supported for provisioners

With the OpenTofu v1.12.0 release we preannounced that WinRM support was deprecated and planned for removal, and now v1.13.0 completes that process by completely removing support for using the WinRM protocol with the remote-exec and file provisioners. Some of the Go libraries that OpenTofu uses for WinRM connection support in provisioners have become unmaintained over time, and so unfortunately we can no longer provide support for this protocol.

If your configuration includes a connection block specifying type = "winrm" then OpenTofu v1.13 will now reject that as an error. We recommend that you migrate to using OpenSSH for Windows before upgrading to OpenTofu v1.13.

Phasing Out Support for 32-bit CPU Architectures

With the OpenTofu v1.12.0 release we preannounced our intention to phase out official releases for 32-bit CPU architectures (386 and arm). OpenTofu v1.13 will be the last series that includes official releases for the affected platforms, and during this series our official releases will produce a warning during tofu init if run on one of the affected platforms.

The forthcoming OpenTofu v1.14 series will not include official packages for these platforms. If you are currently running OpenTofu on a 32-bit CPU architecture then we recommend beginning to plan migration to a 64-bit architecture (e.g. amd64 or arm64) instead.

OpenTofu on macOS requires macOS 13 Ventura

OpenTofu builds for macOS are now supported only on macOS 13 Ventura or later. OpenTofu v1.13 may crash or behave incorrectly on earlier versions of macOS.