Terraform interpolation syntax used to be one of those things you had to memorize early. If you've ever written ${var.name} everywhere, you’ve seen it in action. But modern Terraform has evolved, and the way interpolation works today is both simpler and more powerful.
Let’s walk through how interpolation actually works now, where the old syntax still appears, and how to write cleaner, more maintainable infrastructure code.
What Interpolation Really Means in Terraform
At its core, interpolation is just Terraform’s way of evaluating expressions inside configuration values. It allows you to dynamically construct strings, reference variables, access resource attributes, and call built-in functions.
Here’s a quick example:
1resource "aws_s3_bucket" "example" {
2 bucket = "my-app-${var.environment}-bucket"
3}This combines a static string with a variable. Terraform evaluates it during the plan/apply phase.
The Big Shift: From ${} Everywhere to Native Expressions
Before Terraform 0.12, interpolation required wrapping everything in ${}. That led to configs like this:
1bucket = "${var.project}-${var.environment}"Now, Terraform supports direct expressions without the wrapper in most places:
1bucket = "${var.project}-${var.environment}" # still valid
2bucket = "my-app-${var.environment}" # common pattern
3
4# Or even simpler when not in strings:
5instance_type = var.instance_typeHere’s the key idea:
- Use
${}only inside strings - Outside strings, just reference values directly
This small change makes configurations much easier to read.
Mixing Strings and Expressions
Interpolation shines when building dynamic strings. A common use case is naming resources consistently.
1locals {
2 prefix = "myapp"
3}
4
5resource "aws_instance" "web" {
6 tags = {
7 Name = "${local.prefix}-${var.environment}-web"
8 }
9}Here’s where things get interesting: you can combine multiple sources—locals, variables, and even resource attributes.
1output "instance_info" {
2 value = "Instance ${aws_instance.web.id} is running in ${var.environment}"
3}Using Functions Inside Interpolation
Interpolation isn’t limited to variables. You can call Terraform functions inline.
1resource "aws_s3_bucket" "example" {
2 bucket = "${lower(var.project)}-${random_id.suffix.hex}"
3}Common functions used in interpolation:
lower()/upper()replace()join()format()
For example:
1locals {
2 full_name = format("%s-%s", var.project, var.environment)
3}This often reads cleaner than manual string concatenation.
Interpolation with Lists and Maps
Interpolation becomes even more useful when dealing with collections.
Example with a list:
1variable "subnets" {
2 type = list(string)
3}
4
5output "first_subnet" {
6 value = "Subnet: ${var.subnets[0]}"
7}Example with a map:
1variable "tags" {
2 type = map(string)
3}
4
5output "env_tag" {
6 value = "Environment: ${var.tags["Environment"]}"
7}You can also loop through values using for expressions instead of heavy interpolation.
A Cleaner Alternative: Skip Interpolation When You Can
A common mistake developers make is overusing interpolation where it isn’t needed.
For example:
1# Avoid this
2instance_type = "${var.instance_type}"
3
4# Prefer this
5instance_type = var.instance_typeThe second version is cleaner and avoids unnecessary string wrapping.
Terraform is designed to let expressions stand on their own, not be forced into strings.
Conditional Logic Inside Interpolation
You can embed conditional expressions directly:
1resource "aws_instance" "example" {
2 instance_type = var.environment == "prod" ? "t3.large" : "t3.micro"
3}Inside strings, it looks like this:
1name = "app-${var.environment == "prod" ? "primary" : "dev"}"
2This pattern is useful but can quickly become hard to read. If logic gets complex, move it into locals.
Real-World Pattern: Building Resource Names
Let’s put everything together in a realistic example.
1variable "project" {}
2variable "environment" {}
3
4locals {
5 base_name = format("%s-%s", var.project, var.environment)
6}
7
8resource "aws_s3_bucket" "assets" {
9 bucket = "${local.base_name}-assets"
10
11 tags = {
12 Name = local.base_name
13 Environment = var.environment
14 }
15}This approach avoids messy inline interpolation and keeps naming consistent across resources.
Common Pitfalls to Watch For
- Overusing ${} – Only use it inside strings
- Hard-to-read expressions – Move logic into locals when it grows
- Mixing old and new styles – Stick to modern Terraform syntax
- String coercion surprises – Terraform may convert types implicitly
When Interpolation Still Matters Most
Even with modern expression syntax, interpolation is still essential when:
- Constructing resource names
- Building output messages
- Combining multiple values into a single string
- Formatting identifiers for cloud resources
It’s less about syntax now and more about readability and intent.
Quick Mental Model
If you’re inside quotes, you’re interpolating. If you’re not, you’re just writing an expression.
That one rule clears up most confusion.
Terraform interpolation syntax has become less noisy over time, but understanding it is still key to writing clean, predictable infrastructure code. Once you lean on expressions, functions, and locals instead of cramming everything into strings, your configurations become significantly easier to maintain.