Terraform 1.15 gives module deprecations executable warnings
Terraform 1.15 adds deprecation messages to variables and module outputs. Module authors can warn callers at the point where an old interface is still in use.
Terraform 1.15.0, released on April 29, lets variable and output blocks declare deprecation messages. The release notes specify the two triggers. Passing a value to a deprecated variable produces a warning. Referencing a deprecated output also produces a warning. This gives module authors a way to communicate an interface change during evaluation, where callers can see which configuration still uses it.
Terraform is a daily driver for me, and reusable infrastructure abstractions are a large part of its appeal. I also write providers, so I care about the work involved in maintaining interfaces after other configuration starts depending on them. I want a module author to be able to name a replacement before removing an old input. A warning at the caller's configuration is useful evidence for that transition.
The mechanism cannot decide when removal is safe. That remains an interface maintenance decision for the author and the module consumers. It does let the module carry a message that travels with the configuration users install. I would use that message to explain a concrete migration step and keep a separate record of when the old interface may disappear.
Variables warn when callers supply values
The implementation and tests in pull request 38001 show deprecated as a string containing the warning message. It is not a boolean flag. A variable declaration can therefore explain what the caller should change:
variable "old_name" {
type = string
deprecated = "Use new_name instead."
}
This is a declaration fragment, not a complete migration implementation. It does not create new_name, transfer values into it, or define how two competing inputs should interact. The module author still needs to implement the replacement and specify its behavior. The annotation provides the warning associated with supplying the old variable.
That trigger is appropriate for an input interface. Terraform can identify the caller that continues to set the deprecated variable. An annotation on a declaration should not be read as proof that every existing use has been changed. I would check the diagnostics produced by representative callers before releasing a module that starts warning about a widely used input.
The pull request covers both root variables and variables passed to child modules. That distinction matters for ownership. A root variable can receive its value from the person running the configuration. A child module variable belongs to a reusable interface, and a caller may need to update its module block. The warning needs to tell each reader which input to replace.
I would keep the message specific to the replacement. If a new input has different semantics, merely naming it is insufficient. The message should identify the documentation that explains the change, while that documentation should describe any conversion the caller needs to perform. A deprecation warning is a prompt to review compatibility, not evidence that changing a name preserves behavior.
Outputs carry information to consumers
A deprecated module output has a different direction of use. The module produces the value, and callers reference it in their own expressions. The implementation tracks deprecation information on values so Terraform can warn at those uses. Its tests cover references in resource arguments and local values, among other expression contexts.
Inside a child module, an output declaration can retain the old value while identifying the replacement:
output "old_name" {
value = "example"
deprecated = "Use new_name instead."
}
Here the literal value keeps the example independent of a provider. A real module would retain the appropriate expression for its output. The annotation does not provide the replacement output or establish that its value has an equivalent type. Those are separate parts of the module change that need review.
The implementation also considers forwarding a deprecated output through another deprecated output. This is relevant when modules wrap other modules. A wrapper may need to preserve an existing name for its own callers while explaining a replacement at that level. Its message should describe the wrapper's public interface, because that is the interface its callers can change.
I would test the wrapper together with a caller that still uses the old output. The useful check is whether the warning reaches the expression that consumes the public value and contains an actionable message. Merely checking that the declaration parses would leave the reason for adding the annotation untested.
Deprecation messages need maintenance
The release also improves detection of deprecated resource attributes and blocks, and includes provider-supplied deprecation messages in warnings. Those entries in the release notes concern provider schemas, while variable and output annotations concern module interfaces. Together they give authors more ways to explain why an existing configuration should change.
For me, the main benefit is that the explanation can be attached to the deprecated interface itself. A caller does not have to infer a migration from a generic warning if the author supplies a useful message. That raises the standard for those messages. I would avoid text that merely repeats that an input is deprecated and instead identify the replacement and the relevant compatibility constraint.
There is still a cost to warning volume. A warning that repeats on every run without a clear action can become part of the output people stop reading. I would introduce annotations when a supported replacement exists, then check the module's examples and tests for continued use of the old interface. That makes the warning part of a maintained migration path.
Terraform 1.15.0 also adds official Windows ARM64 builds. The request linked from the release names Windows ARM devices and virtual machines as use cases. This is a separate distribution change, with practical value for users who need that target. It does not change how a module author declares deprecations.
When adopting the new annotations, I would verify the Terraform versions used by module consumers before publishing the changed module. The new syntax belongs to this release's language behavior. The module's compatibility statement and its examples need to agree with that requirement, so callers can distinguish an unsupported executable from a problem in the migration they are attempting.