Skip to main content

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

  1. Avoid overly complex expressions - Break down complex logic into local values for readability
  2. Properly escape quotes - Always double-escape quotes within interpolation expressions in JSON
  3. Consider syntax highlighting limitations - Some editors may not correctly highlight interpolation within JSON
  4. Use external template files for complex scripts - For large scripts with interpolation, prefer templatefile() function
  5. 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.