Interpolation Support
This guide explains how the Terraform Editor API handles interpolation syntax within attribute values across all supported block types.
Overview
The API fully supports Terraform interpolation syntax within attribute values. This allows you to set attributes that reference variables, resources, functions, and other dynamic expressions. The API preserves the correct syntax when outputting the HCL code.
Interpolation syntax is the ${...}
expression pattern used in Terraform to embed expressions within strings or to create dynamic values based on other configuration elements.
Types of Interpolation Supported
Simple References
You can include references to variables, resources, data sources, and other Terraform objects:
"attributes": {
"resource_reference": "${aws_instance.main.id}",
"variable_reference": "${var.name}",
"local_reference": "${local.environment}",
"module_reference": "${module.vpc.subnet_id}",
"data_source_reference": "${data.aws_ami.ubuntu.id}",
"path_reference": "${path.module}",
"terraform_reference": "${terraform.workspace}"
}
The generated HCL preserves these references:
resource_reference = aws_instance.main.id
variable_reference = var.name
local_reference = local.environment
module_reference = module.vpc.subnet_id
data_source_reference = data.aws_ami.ubuntu.id
path_reference = path.module
terraform_reference = terraform.workspace
Array and Object Access
Terraform supports accessing elements of arrays and attributes of objects:
"attributes": {
"array_access": "${var.subnet_ids[count.index]}",
"array_element": "${var.availability_zones[0]}",
"object_attribute": "${var.settings.timeout}",
"nested_attribute": "${aws_instance.main.network_interface[0].access_config[0].assigned_nat_ip}",
"splat_expression": "${aws_instance.web[*].private_ip}"
}
Which generates:
array_access = var.subnet_ids[count.index]
array_element = var.availability_zones[0]
object_attribute = var.settings.timeout
nested_attribute = aws_instance.main.network_interface[0].access_config[0].assigned_nat_ip
splat_expression = aws_instance.web[*].private_ip
Conditional Expressions
The API supports the ternary operator for conditional expressions:
"attributes": {
"conditional": "${var.environment == \"prod\" ? var.prod_instance_type : var.dev_instance_type}",
"nested_conditional": "${var.high_availability ? var.instance_count > 1 ? var.instance_count : 2 : 1}"
}
Which generates:
conditional = var.environment == "prod" ? var.prod_instance_type : var.dev_instance_type
nested_conditional = var.high_availability ? var.instance_count > 1 ? var.instance_count : 2 : 1
Function Calls
The API supports Terraform's built-in functions in interpolations:
"attributes": {
"simple_function": "${upper(var.environment)}",
"function_with_args": "${format(\"%s-instance-%02d\", var.environment, count.index + 1)}",
"nested_function": "${cidrsubnet(var.vpc_cidr, 8, count.index)}",
"chained_function": "${trimspace(file(\"${path.module}/templates/script.sh\"))}"
}
Which generates:
simple_function = upper(var.environment)
function_with_args = format("%s-instance-%02d", var.environment, count.index + 1)
nested_function = cidrsubnet(var.vpc_cidr, 8, count.index)
chained_function = trimspace(file("${path.module}/templates/script.sh"))
Multiple Conditions
Complex conditional expressions with multiple clauses are supported:
"attributes": {
"multiple_conditions": "${var.environment == \"prod\" ? var.prod_size : var.environment == \"staging\" ? var.staging_size : var.dev_size}"
}
Which generates:
multiple_conditions = var.environment == "prod" ? var.prod_size : var.environment == "staging" ? var.staging_size : var.dev_size
Mixed Text and Interpolation
You can combine plain text with interpolation expressions:
"attributes": {
"mixed_conditions": "size-${var.environment == \"prod\" ? \"large\" : \"small\"}-count-${var.high_availability ? \"3\" : \"1\"}",
"mixed_refs": "${var.app_name}-${aws_vpc.main.id}-${data.aws_region.current.name}",
"prefix_suffix": "prefix-${var.name}-suffix",
"text_with_function": "Generated on ${formatdate(\"DD MMM YYYY\", timestamp())}"
}
Which generates:
mixed_conditions = "size-${var.environment == "prod" ? "large" : "small"}-count-${var.high_availability ? "3" : "1"}"
mixed_refs = "${var.app_name}-${aws_vpc.main.id}-${data.aws_region.current.name}"
prefix_suffix = "prefix-${var.name}-suffix"
text_with_function = "Generated on ${formatdate("DD MMM YYYY", timestamp())}"
Escaping Quotes
When your interpolation expressions contain quotes, you need to escape them with backslashes in JSON:
"attributes": {
"with_quotes": "${var.environment == \"prod\" ? \"production\" : \"development\"}"
}
Which generates:
with_quotes = var.environment == "prod" ? "production" : "development"
Special Case: Pure Function Calls
For attributes that are just function calls without the ${}
wrapper, you can omit the interpolation syntax:
"attributes": {
"complex_format": "format(\"%s-instance-%s-%s\", var.project, upper(var.environment), random_id.suffix.hex)"
}
This is equivalent to writing format("%s-instance-%s-%s", var.project, upper(var.environment), random_id.suffix.hex)
in HCL.
Using Interpolation in Different Block Types
In Resource Blocks
{
"edits": {
"add": {
"resource": {
"aws_instance": {
"web": [
{
"add": {
"attributes": {
"ami": "${data.aws_ami.ubuntu.id}",
"instance_type": "${var.instance_type}",
"tags": {
"Name": "${format(\"%s-web-%d\", var.project, count.index)}"
}
}
}
}
]
}
}
}
}
}
In Variable Defaults
{
"edits": {
"add": {
"variable": {
"region_ami": [
{
"add": {
"attributes": {
"type": "map(string)",
"default": {
"us-east-1": "${data.aws_ami.east.id}",
"us-west-1": "${data.aws_ami.west.id}"
}
}
}
}
]
}
}
}
}
In Outputs
{
"edits": {
"add": {
"output": {
"instance_ip": [
{
"add": {
"attributes": {
"value": "${aws_instance.web.private_ip}",
"description": "The private IP of the ${var.environment} instance"
}
}
}
]
}
}
}
}
In .tfvars Files
{
"edits": {
"add": {
"tfvars": [
{
"add": {
"attributes": {
"vpc_name": "${var.environment}-vpc",
"subnet_cidrs": {
"public": "${cidrsubnet(var.vpc_cidr, 8, 0)}",
"private": "${cidrsubnet(var.vpc_cidr, 8, 1)}"
}
}
}
}
]
}
}
}
Advanced Interpolation Examples
Complex Nested Interpolation
"user_data": "${templatefile(\"${path.module}/templates/init.tpl\", { hostname = \"web-${count.index}\", region = var.aws_region, tags = jsonencode(var.tags) })}"
Math Operations
"port": "${6379 + count.index}",
"memory": "${var.base_memory * (count.index + 1)}"
Working with Lists and Maps
"dns_servers": "${concat(var.custom_dns_servers, var.environment == \"prod\" ? var.prod_dns_servers : var.dev_dns_servers)}",
"merged_tags": "${merge(var.common_tags, var.environment_tags[var.environment])}"
Best Practices
- Avoid overly complex expressions - Break down complex logic into local values for readability
- Properly escape quotes - Always double-escape quotes within interpolation expressions in JSON
- Consider syntax highlighting limitations - Some editors may not correctly highlight interpolation within JSON
- Use external template files for complex scripts - For large scripts with interpolation, prefer
templatefile()
function - Consider readability - Sometimes separate attributes with computed values are clearer than complex interpolation
Troubleshooting
Common issues when working with interpolation:
- Incorrect escaping - Missing or incorrect backslashes for quotes in JSON
- Unmatched brackets - Ensure all
${
have matching}
- Type errors - Interpolated values must be of the correct type for the context
- Incorrect references - Verify the resources, variables, or data sources being referenced exist
Conclusion
The Terraform Editor API's support for interpolation syntax enables you to create dynamic, flexible Terraform configurations that can adapt to different environments and conditions. This allows your API clients to leverage the full power of Terraform's expression language when generating infrastructure as code.