Terraform

How to Use Terraform Merge Function – Examples

How to Use Terraform Merge Function - Examples

🚀 Level Up Your Infrastructure Skills

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

In Terraform, a “function” refers to a built-in or user-defined operation that can be performed on input values to produce an output value. Functions in Terraform allow you to manipulate data, perform calculations, and create more dynamic configurations. They are an essential part of the Terraform language and can be used within expressions to achieve various tasks.

In this article, we will take a look at what the Terraform merge function is and how to use it, with a few useful practical examples showing how to merge lists of maps, lists of objects, and apply merged lists of tags to cloud resources.

What we’ll cover:

  1. What is merge in Terraform?
  2. How to use Terraform merge
  3. Shallow vs. deep merging in Terraform
  4. Best practices for using the Terraform merge function

What is merge in Terraform?

Terraform merge is a built-in function that takes an arbitrary number of maps or objects and returns a single map or object containing a merged set of elements from all arguments. If the same key appears in multiple maps, the value from the later map overrides earlier ones. 

It’s useful for modular configuration and dynamic variable injection.

Keep in mind that the merge function is available in Terraform versions 0.12 and later. If you are using an earlier version of Terraform, you might need to use alternative methods like the concat function or the for expression to achieve similar merging behavior.

How to use Terraform merge

Let’s explore how to practically use Terraform merge with a few examples.

Example 1: Terraform merge maps

In Terraform, we define a map of objects within {}.

We can use the merge function by defining the maps we want to merge:

merge(map1, map2, ...)

Consider we have two maps of objects we want to merge together defined in our Terraform locals declaration:

locals {
  map1 = {
    luke  = "jedi"
    yoda  = "jedi"
    darth = "sith"
  },
  map2 = {
    quigon     = "jedi"
    palpantine = "sith"
    hansolo    = "chancer"
  }
}

We can use the merge function like so:

merged_map = merge(local.map1, local.map2)

Which would produce the following value for merged_map:

merged_map = {
  luke       = "jedi"
  yoda       = "jedi"
  darth      = "sith"
  quigon     = "jedi"
  palpantine = "sith"
  hansolo    = "chancer"
}

Note that when merging maps, if there are duplicate keys between the input maps, the value from the last map provided as an argument will take precedence.

In other words, if the input maps contain conflicting keys, the value from the rightmost map will be used in the merged map.

For example, in our example above, if we defined the value as jedi for the key darth again in map2 (controversial!) — then the resulting output would be darth = "jedi".

Example 2: Terraform merge multiple maps

The merge function accepts any number of map arguments and returns a single combined map. If keys overlap, the later map’s value overrides the earlier one. 

For example:

variable "map1" {
  default = {
    a = 1
    b = 2
  }
}

variable "map2" {
  default = {
    b = 3
    c = 4
  }
}

output "merged" {
  value = merge(var.map1, var.map2)
}

This returns { a = 1, b = 3, c = 4 }

For dynamic or nested merges, use merge() within loops or combine with for expressions as needed.

Example 3: Terraform merge lists of objects

Terraform does not have a built-in function to directly merge lists of objects. However, there are a few techniques you can use to achieve this behavior. Which way you choose will depend on the structure of your data (i.e., how you have defined your lists).

One way is to use the concat function to take two or more lists and combine them into a single list.

locals {
  list1 = [
    { key = "luke", value = "jedi" },
    { key = "yoda", value = "jedi" }
  ]

  list2 = [
    { key = "darth", value = "sith" },
    { key = "palpatine", value = "sith" }
  ]

  merged_list = merge({ for elem in concat(local.list1, local.list2) : elem.key => elem })
}

merged_list will result in the following output:

[
  { key = "luke", value = "jedi" },
  { key = "yoda", value = "jedi" },
  { key = "darth", value = "sith" },
  { key = "palpatine", value = "sith" }
]

You could also use the for expression, which will result in the same output for merged_list:

locals {
  list1 = [
    { key = "luke", value = "jedi" },
    { key = "yoda", value = "jedi" }
  ]

  list2 = [
    { key = "darth", value = "sith" },
    { key = "palpatine", value = "sith" }
  ]

  merged_list = { for elem in concat(local.list1, local.list2) : elem.key => elem.value }}
}

Another way to achieve the same output is to use the flatten function:

locals {
  list_of_lists = [
    [
      { key = "luke", value = "jedi" },
      { key = "yoda", value = "jedi" }
    ],
    [
      { key = "darth", value = "sith" },
      { key = "palpatine", value = "sith" }
    ]
  ]

  merged_list = flatten(local.list_of_lists)
}

Example 4: Terraform merge lists of maps

To merge lists of maps in Terraform, use the flatten and merge functions together with for expressions to iterate through and combine each map.

Going back to the previous examples, the following will again result in the same output:

locals {
  list1 = [
    { key = "luke", value = "jedi" },
    { key = "yoda", value = "jedi" }
  ]

  list2 = [
    { key = "darth", value = "sith" },
    { key = "palpatine", value = "sith" }
  ]

  merged_list = { for elem in concat(local.list1, local.list2) : elem.key => elem.value }}
}

Here, merged_list will result in the following output:

[
  { key = "luke", value = "jedi" },
  { key = "yoda", value = "jedi" },
  { key = "darth", value = "sith" },
  { key = "palpatine", value = "sith" }
]

Example 5: Terraform merge tags

One common use case for using the merge function is to merge together lists of tags applied to cloud resources.

locals {
  default_tags = {
    Environment = "Production"
    Project     = "MyProject"
  }

  additional_tags = {
    CostCenter = "12345"
    Department = "Engineering"
  }

  merged_tags = merge(local.default_tags, local.additional_tags)
}

This will result in merged_tags containing the combined list which can then be applied to the resource as needed.

{
  Environment = "Production"
  Project     = "MyProject"
  CostCenter  = "12345"
  Department  = "Engineering"
}

The examples below show the list of merged_tags applied to the example AWS EC2 instance example1, where instance example2 will only have the default_tags applied.

resource "aws_instance" "example1" {
  ami           = "ami-0c55b159cbfafe1f0" # Replace with the AMI ID of your desired instance
  instance_type = "t2.micro"               # Replace with your desired instance type
  subnet_id     = "subnet-12345678"        # Replace with the subnet ID where you want to launch the instance

  tags = local.merged_tags
}

resource "aws_instance" "example2" {
  ami           = "ami-0c55b159cbfafe1f0" # Replace with the AMI ID of your desired instance
  instance_type = "t2.micro"               # Replace with your desired instance type
  subnet_id     = "subnet-12345678"        # Replace with the subnet ID where you want to launch the instance

  tags = local.default_tags
}

Shallow vs. deep merging in Terraform

Shallow merging in Terraform replaces entire nested values at a given key, while deep merging recursively combines nested maps or objects. Terraform’s built-in merge() function performs only shallow merges.

With shallow merging, if two maps share a key whose value is another map, the second map fully replaces the first at that key. 

In contrast, deep merging combines both maps at all levels, preserving non-conflicting keys. For example, merging {"tags": {"env": "prod"}} with {"tags": {"owner": "dev"}} yields {"tags": {"owner": "dev"}} using shallow merging, but {"tags": {"env": "prod", "owner": "dev"}} using deep merging.

Best practices for using the Terraform merge function

Here are practical tips to use Terraform’s merge function effectively when combining multiple configuration maps:

  • Understand key precedence: When keys overlap, values from later maps in the argument list take precedence. This is useful for layering environment-specific settings over shared defaults.
  • Avoid type confusion: All arguments must be maps. If combining dynamic values, use tomap() to ensure type consistency.
  • Use for module inputs: merge is often used to simplify module input by combining global and local variable maps.
  • Handle nulls gracefully: Use the null coalescing operator (??) when dealing with optional inputs to avoid passing null maps.

Key points

In this post, we covered another Terraform functionmerge, and learned what it is and how to use it. We went through examples showing how to merge lists of maps, lists of objects and apply merged lists of tags to cloud resources.

Terraform is really powerful, but to achieve an end-to-end secure GitOps approach, you need to use a product that can run your Terraform workflows. Spacelift takes managing Terraform to the next level by giving you access to a powerful CI/CD workflow and unlocking features such as:

  • Policies (based on Open Policy Agent)
  • Multi-IaC workflows
  • Self-service infrastructure
  • Integrations with any third-party tools

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.

Start free trial

Frequently asked questions

  • How does merge handle duplicate keys in order of precedence?

    When using the Terraform merge() function, duplicate keys are resolved by last-write-wins order, meaning later maps in the argument list take precedence over earlier ones.

    This behavior ensures that if multiple maps contain the same key, the value from the last map provided will overwrite the previous ones. Terraform processes the arguments from left to right and applies values accordingly.

  • How do I merge two Terraform state files?

    To merge two Terraform state files, you typically use the terraform state subcommands, such as terraform state mv or terraform import, to move or import resources from one state into another. Terraform does not provide an automatic or built-in merge function, so this process must be done manually and carefully to avoid conflicts or inconsistencies. It’s important to back up both state files and verify resource mappings before making changes.

Terraform Functions Cheat Sheet

Grab our ultimate cheat sheet PDF for all
the Terraform functions you need on hand.

Share your data and download the cheat sheet