Terraform 1.15 Introduces Dynamic Module Sources and Variable Deprecation
Introduction
Terraform 1.15 brings two significant enhancements that improve module flexibility and lifecycle management. The first allows practitioners to use variables directly in module source declarations, enabling dynamic module selection during initialization. The second introduces a formal deprecation mechanism for variables and outputs, helping module authors communicate changes gracefully. This article explores both features with practical examples and explains how they streamline infrastructure as code workflows.
Dynamic Module Sources with Const Variables
Previously, module sources had to be static strings or use interpolation only with values known before terraform init. Terraform 1.15 changes this by allowing variables—provided they are marked with the new const attribute—to appear in module source paths and version constraints.
How the const Attribute Works
The const attribute is a boolean flag you add to a variable block. When set to true, the variable can be evaluated during terraform init. This is distinct from regular variables, which are only available later during plan/apply. The const attribute is mutually exclusive with sensitive and ephemeral—you cannot combine them.
variable "folder" {
type = string
const = true
}
This variable can then be used in a module source like so:
module "zoo" {
source = "./${var.folder}"
}
During terraform init, Terraform will resolve var.folder and fetch the appropriate module. This enables scenarios like selecting different module implementations based on environment or deployment context, all without altering the root configuration structure.
Usage in Nested Modules
The feature extends to nested modules as well. If a child module declares an input variable with const = true, that variable can be used in its own module sources. However, Terraform imposes a clean chain: every variable that flows into a module source path must be explicitly marked const at each intermediate level. This ensures the dependency graph remains predictable during initialization.
Limitations and Error Handling
If you reference a non-constant variable or a local value inside a module source, Terraform will emit an error during init. Only simple variables with the const attribute are permitted. This prevents ambiguous situations where the source path would depend on runtime computations. The error message clearly points to the offending reference, helping you quickly fix the configuration.
Deprecating Variables and Outputs
Module authors often need to phase out old variables and outputs while giving users time to migrate. Terraform 1.15 introduces the deprecated attribute for both variable and output blocks. When set, any usage triggers a warning during validation, not just at runtime.
The deprecated Attribute
You add the deprecated attribute with a string message that explains why the item is deprecated and what to use instead. For example:
variable "bad" {
deprecated = "Please use 'good' instead, this variable will be removed"
}
output "old" {
value = ...
deprecated = "Please use 'new' instead, this output will be removed"
}
When Terraform validates the configuration, it checks for any references to deprecated variables or outputs. If a variable is deprecated, warnings appear when a value is passed to it—whether via CLI, environment variables, or a module call. For outputs, any reference to the deprecated output in expressions or other outputs triggers a warning.
Example and Diagnostics
Consider the following nested setup:
# mod/main.tf
variable "bad" {
deprecated = "Please use 'good' instead"
}
output "old" {
value = "deprecated value"
deprecated = "Please use 'new' instead"
}
# main.tf
variable "root" {
deprecated = "This should no longer be used."
}
module "myModule" {
source = "./mod"
bad = "not good"
}
locals {
moduleUsage = module.myModule.old
}
During validation, Terraform emits warnings for:
- var.root – because a value may be assigned externally (e.g., via environment variable).
- module.myModule.bad – because a value is passed to the deprecated variable.
- locals.moduleUsage – because it references the deprecated output
module.myModule.old.
If a deprecated output is itself referenced within another deprecated output, only the outermost deprecated item triggers a warning. This allows module authors to chain deprecations without overwhelming users with repeated warnings.
Chaining Deprecations for Outputs
You can define an output that is itself deprecated and depends on another deprecated output. For instance:
# mod/main.tf
output "old" {
value = "internal"
deprecated = "Please use 'new' instead"
}
# main.tf
module "myModule" {
source = "./mod"
}
output "ancient" {
value = module.myModule.old
deprecated = "Please stop using this"
}
When a user references output.ancient, they see only one warning—about ancient being deprecated. The internal deprecation of old is not separately reported because the value flows through a deprecated output. This design helps teams manage multi‑version transitions smoothly.
Conclusion
Terraform 1.15 empowers practitioners with dynamic module sources through the const variable attribute, enabling more flexible module selection without sacrificing init‑time predictability. At the same time, the new deprecated attribute for variables and outputs gives module authors a first‑class way to phase out old interfaces while warning users in a controlled manner. Both features enhance the overall maintainability and clarity of Terraform configurations. Upgrading to 1.15 unlocks these capabilities today.