[Live Q&A] Top Questions of Teams Switching from HCP/TFE to Spacelift

➡️ Register Now

How to Use Terraform Concat Function [Examples]

terraform

🚀 Level Up Your Infrastructure Skills

You focus on building. We’ll keep you updated. Get curated infrastructure insights that help you make smarter decisions.

Terraform’s concat() function lets you merge multiple lists into one, making your infrastructure code more dynamic and reusable. In the examples below, we show how to use concat() effectively.

What is the Terraform concat function?

The Terraform concat function is used to merge two or more lists into a single list. It does not flatten nested lists, but instead joins them in the order they are provided. It is commonly used when dynamically generating values such as resource names, tags, or availability zones.  All inputs must have compatible element types (e.g., all strings).

For example:

variable "list1" {
  default = ["a", "b"]
}

variable "list2" {
  default = ["c", "d"]
}

output "combined" {
  value = concat(var.list1, var.list2)
}

This produces ["a", "b", "c", "d"].

What is the difference between concat and merge in Terraform?

In Terraform, concat joins multiple lists (or other sequences) into a single flat list, while merge combines multiple maps into one map. They operate on different data types and are not interchangeable. If keys overlap in merge, later values override earlier ones. 

If you’re working with maps (like tags), merge is usually simpler than building lists and transforming them.

Key notes about Terraform concat

  • concat() works on sequence types (lists/tuples; sets should be converted with tolist() because their order is undefined).
  • The function does not flatten nested lists; it just appends inputs in order.
    If you need to flatten nested lists, use the flatten() function in conjunction.
  • join() does not concatenate strings; it turns a list of strings into a single string with a delimiter. To concatenate strings, use interpolation like ${var.a}${var.b}" or format().
  • Inputs must have compatible element types (e.g., don’t mix numbers and strings).

Example 1: Concatenating lists of strings for security group rules

Let’s suppose you are defining AWS Security Group rules and want to allow traffic from a list of predefined CIDR blocks. Some of these come from a default list, and others are project-specific. You want to combine them into a single list to apply to your security group.

variable "default_cidrs" {
  default = ["10.0.0.0/16", "192.168.0.0/16"]
}

variable "project_cidrs" {
  default = ["172.16.0.0/12"]
}

resource "aws_security_group" "example" {
  name        = "example-sg"
  description = "Security group with combined CIDR rules"
  vpc_id      = "vpc-123456"

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = concat(var.default_cidrs, var.project_cidrs)
  }
}

In this example, we define two separate variables default_cidrs and project_cidrs. The concat function combines them into a single list of CIDR blocks to be used in the cidr_blocks attribute. 

This avoids manually merging the lists and makes the configuration more modular and reusable. It’s especially useful if the project_cidrs are dynamic or optional.

Example 2: Concatenating strings in lists for usernames

For this example, imagine you are provisioning multiple users and want to assign them usernames based on a common prefix and a list of roles. Instead of writing each username manually, you use Terraform’s concat function along with other helpers to automate it.

locals {
  admins  = ["alice", "bob"]
  devs    = ["carol", "dave"]
  users   = concat(local.admins, local.devs)
}

output "user_list" {
  value = local.users
}

Here, the concat function is used to merge the admins and devs lists into a single users list. This could then be used to provision IAM users, assign policies, or generate usernames. 

This approach scales well: if you add another category like qa = ["eve"], you just add it to the concat() call. It keeps your logic clean and your Terraform code DRY (Don’t Repeat Yourself).

Example 3: Dynamic tagging of EC2 instances based on environment

In many Terraform-based infrastructures, tagging EC2 instances is essential for organization, billing, and automation. Commonly, some tags are shared across all environments (e.g., "Project", "Terraform"), while others vary per environment (e.g., "Environment", "Team"). 

Hardcoding these repeatedly is error-prone and inefficient. Instead, using Terraform’s concat function, we can cleanly merge these tag lists into a unified set.

variable "environment" {
  type    = string
  default = "development"
}

variable "common_tags" {
  type    = list(object({
    key   = string
    value = string
  }))
  default = [
    { key = "Project",     value = "CustomerApp" },
    { key = "Terraform",   value = "true" }
  ]
}

variable "env_specific_tags" {
  type = map(list(object({
    key   = string
    value = string
  })))
  default = {
    development = [
      { key = "Environment", value = "dev" },
      { key = "Team",        value = "DevTeam" }
    ],
    staging = [
      { key = "Environment", value = "staging" },
      { key = "Team",        value = "QA" }
    ],
    production = [
      { key = "Environment", value = "prod" },
      { key = "Team",        value = "Ops" }
    ]
  }
}

resource "aws_instance" "app_server" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  tags = { for tag in concat(
              var.common_tags,
              lookup(var.env_specific_tags, var.environment, [])
           )
           : tag.key => tag.value

The common_tags variable holds a list of tag objects that are applied to all EC2 instances, regardless of environment. Meanwhile, env_specific_tags is a map that defines environment-specific tag sets. These tags vary depending on whether the instance is deployed in development, staging, or production.

The concat function is used to merge common_tags with the environment-specific list selected using the lookup function. This ensures a safe default of an empty list ([]) if the specified environment key doesn’t exist in the map, preventing errors.

Key points

Using the concat function in Terraform improves code modularity and reusability by dynamically combining static and environment-specific configurations. It reduces duplication, simplifies environment management, and makes your infrastructure code easier to maintain and scale.

We encourage you to explore how Spacelift makes it easy to work with Terraform. If you need help managing your Terraform infrastructure, building more complex workflows based on Terraform, and managing AWS credentials per run, instead of using a static pair on your local machine, Spacelift is a fantastic tool for this.

If you want to learn more about Spacelift, create a free account today or book a demo with one of our engineers.

Note: New versions of Terraform are placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that expands on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6.

Manage Terraform better with Spacelift

Build more complex workflows based on Terraform using policy as code, programmatic configuration, context sharing, drift detection, resource visualization and many more.

Learn more

The Practitioner’s Guide to Scaling Infrastructure as Code

Transform your IaC management to scale

securely, efficiently, and productively

into the future.

ebook global banner
Share your data and download the guide