-
Notifications
You must be signed in to change notification settings - Fork 10.2k
Description
Terraform Version
Terraform v1.14.3Use Cases
Terraform variables are values, not expressions. If a user passes a string that looks like an expression (e.g., ${upper("test")}), Terraform treats it as a literal string (or it is rejected depending on context). There is currently no supported mechanism to:
- Pass an expression via a variable (including Terraform functions), and
- Have Terraform evaluate that expression when the variable is used as an argument to a resource or module.
This prevents certain “configuration-driven indirection” patterns, such as:
- Passing a naming rule or formatting rule as configuration
- Having a module accept a “value expression” to compute a final name/path/ID
- Avoiding repeated boilerplate expressions across multiple call sites/resources
- Driving transformations from environment configuration without duplicating expression logic
variable "function_name_rule" {
type = string
}
# Caller wants:
# function_name_rule = "$${upper(var.base_name)}"
resource "aws_lambda_function" "example" {
function_name = var.function_name_rule # would be ideal if evaluated here
}
Attempted Solutions
Using interpolation-like syntax inside a string, such as:
function_name_rule = "$${upper("test")}"
Terraform currently treats this as a literal string; there is no supported evaluation step to interpret it as an expression.
- Workarounds like locals or duplicating the expression at each use site defeat the goal of configuration-driven reuse.
Proposal
Introduce an opt-in, explicit way to represent deferred expressions as a distinct type/value that can be passed through variables and evaluated at the point of use in resource/module arguments.
Option A: New Expression Value Constructor + Explicit Evaluation
Call site:
variable "name_expr" {
type = expr(string) # or a dedicated expression type
}
module "x" {
source = "./x"
name_expr = expr(upper("test"))
}
Inside module or resource usage:
resource "aws_lambda_function" "example" {
function_name = eval(var.name_expr)
}
Properties:
- expr(...) produces an expression value (not a string)
- eval(...) explicitly evaluates it in the current scope at the point of use
- Terraform can validate types (expr(string)), and prevent arbitrary evaluation where not permitted
- Keeps evaluation explicit (no “magic string interpolation”)
Option B: String-Based Deferred Interpolation
Allow a string convention like $${ ... } anywhere variables are used, and evaluate it at use sites. Example:
function_name = "$${upper("test")}"
This is more ergonomic, but is also more ambiguous, harder to statically analyze, and risks confusing “data” vs “code”.
Why This Is Useful
- Enables reusable “rules” for naming/formatting without repeating expressions
- Allows modules to accept transformation logic from callers in a controlled way
- Improves ergonomics for environments with strong naming conventions
- Keeps dependency graph correctness if expression evaluation still flows through Terraform’s standard expression model
References
No response