July 16th Virtual Panel: Rethinking IaC Pipelines for Control, Scale, and Sanity

➡️ Register Now

Terraform

Terraform Map Variable – What It is & How to Use

Terraform Map Variable - What It is & How to Use

🚀 Level Up Your Infrastructure Skills

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

Maps are a fundamental data type in Terraform’s HashiCorp Configuration Language (HCL), which is used to define infrastructure as code (IaC) in Terraform. They are useful when you want to associate a key with a specific value, especially when working with dynamic or repeatable resources.

In this article, we will examine map variables, explaining what they are, why you would use them, and the differences between other key data structure types in Terraform. 

We will also provide some practical examples of how to use a map, how to use a map with local values, and how to use Terraform functions to manipulate your map output.

What we will cover:

  1. What is a map in Terraform?
  2. How to use the Terraform map
  3. Map variable with local values
  4. How to convert a list to a map in Terraform
  5. How to use the Terraform flatten function with a map
  6. How to use the Terraform map and tomap functions
  7. What is the Terraform map function?

What is a map in Terraform?

A Terraform map variable is a key-value data structure that groups related values under a single variable, allowing structured access to configuration data.

Maps are commonly used in Terraform to store configuration data, define variables, and pass information between different parts of your code.

When defining your map variable, you can also set the type annotation. The following types can be used to define your map:

  1. map(string): The values in the map are of type “string.”
  2. map(number): The values in the map are of type “number” (integer or floating-point).
  3. map(bool): The values in the map are of type “bool” (true or false).
  4. map(list): The values in the map are lists (arrays) containing elements of the same type.
  5. map(set): The values in the map are sets containing unique elements of the same type.
  6. map(object({ ... })): The values in the map are objects (complex data structures) that must conform to a specific structure defined by the object’s attributes.

What is the difference between map and object?

While maps and objects have similar syntax (both use curly braces {} and key-value pairs), their intended purposes and where they are typically used in Terraform are distinct. A map in Terraform is a simple key-value structure where all values must be of the same type. An object, by contrast, defines a schema with named attributes that can each have different types.

Objects are mainly used to represent and manage resource attributes in Terraform providers, where the provider uses the object to understand the properties of a resource being managed.

As an example, the code below creates an AWS EC2 instance. The tags attribute of the resource would be considered an ‘object’.

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

  tags = {
    Name        = "Example Instance"
    Environment = "Production"
  }
}

What is the difference between map(string) and map(object)?

The difference between map(string) and map(object) refer to different types of maps with distinct purposes.  

map(string) defines a map where all values must be strings, while map(object({...})) allows values to be structured objects with multiple typed attributes. In this context, “object” means a complex data structure that can have multiple attributes represented by key-value pairs.

The “object” type is typically used when you want to define structured data with multiple attributes for each key in the map.

type = map(string)

Let’s check out some examples of each!

How to use Terraform map

A map in Terraform is defined using curly braces {} and consists of zero or more key-value pairs. Each key in the map must be unique, and the values can be of any data type supported by Terraform, such as strings, numbers, lists, or even nested maps.

Example 1 – Map of string

The example below shows a simple map of type string in Terraform:

variable "force_map" {
  type = map(string)
  default = {
    luke  = "jedi"
    yoda  = "jedi"
    darth = "sith"
  }
}

In this example, we define a variable named force_map with the type map(string), indicating that it is a map with string values.

The map contains three key-value pairs (the keys are luke, yoda and darth, and the values are specified for each as jedi, jedi and sith). Values are simple strings associated with each key.

You can use the keys to access the values in the map. For example, to access the value corresponding to ‘yoda’ in the force_map variable, you would use ${var.force_map["yoda"]}. This would return jedi!

Example 2 – Map of object

The example below shows a map of type ‘object’. Values are complex objects with multiple attributes represented by key-value pairs.

variable "example_map" {
  type = map(object({
    name = string
    enemies_destroyed = number
    badguy = bool
  }))
  default = {
    key1 = {
      name = "luke"
      enemies_destroyed = 4252
      badguy = false
    }
    key2 = {
      name = "yoda"
      enemies_destroyed = 900
      badguy = false
    }
    key3 = {
      name = "darth"
      enemies_destroyed=  20000056894
      badguy = true
    }
  }
}

Each key in the example above (key1, key2 and key3) is associated with a complex object having attributes “name,” “enemies_destroyed,” and “badguy”, each value having a different data types (string, number and bool).

Example 3 – Map of lists

The next example shows a map of lists, which contain values of type string:

variable "lightsabre_color_map" {
  type = map(list(string))
  default = {
    luke = ["green", "blue"]
    yoda = ["green"]
    darth = ["red"]
  }
}

This could also be achieved with a map using the ‘set’ type:

variable "lightsabre_color_map" {
  type = map(set(string))
  default = {
    luke = ["green", "blue"]
    yoda = ["green"]
    darth = ["red"]
  }
}

Map variable with local values

You can use a map with Terraform local values to store data that you want to use within your configuration without repeating the computation. Using local values helps to keep your code clean, readable, and more maintainable.

In the below example, we generate a name for an AWS S3 bucket resource using the number of enemies each character has destroyed.

# The list of characters and their corresponding enemies destroyed
variable "enemies_map" {
  type = map(number)
  default = {
    luke  = 4252
    yoda  = 900
    darth = 20000056894
  }
}

locals {
  # Computed names for each bucket
  bucket_names = {
    for name, destroyed in var.enemies_map :
    name=> "${name}-bucket"
  }
}

resource "aws_s3_bucket" "buckets" {
  for_each = local.bucket_names

  bucket = each.value
  acl    = "private"
}

How to convert a list to a map in Terraform

You can convert a list to a map using the for expression and the toset() function.

The Terraform toset() function converts a list into a set, which can then be used to create a map with unique keys and associated values. This conversion is necessary in situations where a map in Terraform requires unique keys and a list has duplicate elements.

In the example below, we have two lists defined in our locals: characters and enemies_destroyed, which we want to convert to a map.

locals {
  characters = ["luke", "yoda", "darth"]
  enemies_destroyed = [4252, 900, 20000056894]

  map = {
    for index, character in toset(local.characters) : # Convert character list to a set
      character => local.enemies_destroyed[index]
  }
}

The for expression is used to loop over the set to create the map, where we use characters as the key and enemies_destroyed as the value.

This results in the following map:

{
  "luke"  = 4252
  "yoda" = 900
  "darth" = 20000056894
}

To avoid runtime errors when converting lists to maps in Terraform, follow the best practices below:

  1. Use for expressions with clear key-value mappings: When converting a list to a map, ensure that each element in the list contains enough structure to derive a unique key.
  2. Ensure key uniqueness: Keys in a map must be unique. When using a property from list elements as the map key (e.g., user.id), validate or sanitize input if necessary.
  3. Handle complex structures with object unpacking: If the list contains objects, use property unpacking to map meaningfully
  4. Use conditionals cautiously in for expressions:
    Include filters only when relevant, to avoid introducing sparse maps or unexpected null values.
  5. Prefer clarity over compactness: Avoid deeply nested or overly concise expressions that hinder maintainability.

How to use the Terraform flatten function with a map

To convert your map or nested list back into a flat list, use the Terraform flatten() function.

When applied to a map, the flatten function flattens the map into a list of key-value pairs represented as a list of lists. Each sublist contains two elements: the key and the corresponding value from the original map.

In the example below, we use the flatten function again with the for expression to iterate over the key-value pairs in the enemies_map.

locals {
  enemies_map= {
    luke  = 4252
    yoda  = 900
    darth = 20000056894
  }

  flattened_enemies_map = flatten([
    for key, value in local.enemies_map:
    [key, value]
  ])
}

The resulting flat list looks like this:

[
  "luke", 4252,
  "yoda", 900,
  "darth", 20000056894,
]

How to use Terraform map and tomap functions

We can also use the Terraform tomap function to convert other data types to maps. It can be used to convert a single object or a single-element list into a map, where each attribute of the object becomes a key-value pair in the resulting map.

In the example below, we have our enemies_list defined as type list. We can use the tomap function to convert this to a list where the name is the key and enemies_destroyed is the value.

locals {
  enemies_list = [
    { name = "luke",  enemies_destroyed = 4252 },
    { name = "yoda", enemies_destroyed = 900},
    { name = "darth", enemies_destroyed = 20000056894},
  ]

  map = tomap({
    for character in local.enemies_list:
    character.name => character.enemies_destroyed
  })
}

Note that because a map requires all of the elements to be of the same type, mixed-type elements will be converted to the most general type. For example, if we had a list containing strings and boolean values, using tomap would result in the values all being strings:

tomap({"character" = "luke", "badguy" = false})

# Output:
{
  "a" = "luke"
  "b" = "false"
}

What is the Terraform map function?

The map() function in older Terraform versions created a map from a sequence of key-value pairs, for example, map("env", "prod", "region", "us-west-1"). It was a variadic function, which made it convenient for defining small inline maps quickly.

However, starting with Terraform 0.12, the map() function was removed. This change was due to the introduction of native map syntax using curly braces {}, such as:

{
  env    = "prod"
  region = "us-west-1"
}

The native map syntax is more readable, supports complex expressions, and aligns better with HCL2’s consistent data types, making the map() function redundant.

Managing Terraform resources with Spacelift

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) – You can control how many approvals you need for runs, what kind of resources you can create, and what kind of parameters these resources can have, and you can also control the behavior when a pull request is open or merged.
  • Multi-IaC workflows – Combine Terraform with Kubernetes, Ansible, and other infrastructure-as-code (IaC) tools such as OpenTofu, Pulumi, and CloudFormation,  create dependencies among them, and share outputs
  • Build self-service infrastructure – You can use Blueprints to build self-service infrastructure; simply complete a form to provision infrastructure based on Terraform and other supported tools.
  • Integrations with any third-party tools – You can integrate with your favorite third-party tools and even build policies for them. For example, see how to integrate security tools in your workflows using Custom Inputs.
picnic-blog-banner

As it pursues its mission to transform grocery delivery logistics technology, Picnic Technologies wants to free its infrastructure team to do impactful work. Spacelift helps them to create the infrastructure they need, without the pain of manual Terraform processes. Now developers can work efficiently on more enjoyable work.

Spacelift customer case study

Read the full story

Spacelift enables you to create private workers inside your infrastructure, which helps you execute Spacelift-related workflows on your end. Read the documentation for more information on configuring private workers.

You can check it out for free by creating a trial account or booking a demo with one of our engineers.

Key Points

In Terraform, a map is a data structure used to represent a collection of key-value pairs and is commonly used to store configuration data, define variables, and pass information between different parts of your infrastructure code.

A map in Terraform is always defined using curly braces {} and consists of zero or more key-value pairs. Each key in the map must be unique, and the values can be of any data type supported by Terraform, such as strings, numbers, lists, or even nested maps.

You can convert data to or from maps, using Terraform’s built-in functions as required.

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