Terraform Tutorial — Lists, Maps, and Objects

2 minute read

Beyond strings, numbers, and booleans, Terraform supports collection types — lists, maps, sets, and objects. These let you work with groups of values, which is essential for managing multiple resources, tags, and configuration sets.


Lists (Tuples)

A list is an ordered collection of values:

variable "availability_zones" {
  type    = list(string)
  default = ["us-east-1a", "us-east-1b", "us-east-1c"]
}

Accessing List Elements

Use zero-based indexing:

# First element
first_az = var.availability_zones[0]    # "us-east-1a"

# Last element (using length)
last_az = var.availability_zones[length(var.availability_zones) - 1]

List of Other Types

# List of numbers
variable "ports" {
  type    = list(number)
  default = [80, 443, 8080]
}

# List of booleans
variable "flags" {
  type    = list(bool)
  default = [true, false, true]
}

Maps

A map is a collection of key-value pairs where all keys are strings:

variable "tags" {
  type = map(string)
  default = {
    Name        = "web-server"
    Environment = "dev"
    Team        = "backend"
  }
}

Accessing Map Values

# Bracket notation
env = var.tags["Environment"]    # "dev"

# Dot notation (only works for simple keys without special characters)
env = var.tags.Environment       # "dev"

Map of Numbers

variable "instance_counts" {
  type = map(number)
  default = {
    dev     = 1
    staging = 2
    prod    = 5
  }
}

# Usage
count = var.instance_counts[var.environment]

Objects

An object is like a map but with a defined structure — each key has a specific type:

variable "database_config" {
  type = object({
    engine         = string
    engine_version = string
    instance_class = string
    allocated_storage = number
    multi_az       = bool
  })

  default = {
    engine            = "postgres"
    engine_version    = "15.4"
    instance_class    = "db.t3.micro"
    allocated_storage = 20
    multi_az          = false
  }
}

Access object attributes with dot notation:

engine = var.database_config.engine           # "postgres"
size   = var.database_config.allocated_storage # 20

Sets

A set is like a list but with no duplicates and no guaranteed order:

variable "allowed_cidrs" {
  type    = set(string)
  default = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
}

Sets are useful with for_each (which requires a set or map, not a list). Convert a list to a set with toset():

for_each = toset(var.server_names)

Complex Types

You can nest types to create complex structures:

# List of objects
variable "users" {
  type = list(object({
    name  = string
    email = string
    admin = bool
  }))

  default = [
    { name = "alice", email = "alice@example.com", admin = true },
    { name = "bob",   email = "bob@example.com",   admin = false },
  ]
}

# Map of lists
variable "security_group_rules" {
  type = map(list(number))
  default = {
    http  = [80, 80]
    https = [443, 443]
    ssh   = [22, 22]
  }
}

Useful Collection Functions

HCL has built-in functions for working with collections:

length()

Returns the number of elements:

count = length(var.availability_zones)    # 3

merge()

Combines two or more maps:

locals {
  default_tags = {
    ManagedBy = "terraform"
    Project   = "web-app"
  }

  environment_tags = {
    Environment = var.environment
  }

  all_tags = merge(local.default_tags, local.environment_tags)
  # { ManagedBy = "terraform", Project = "web-app", Environment = "dev" }
}

concat()

Combines two or more lists:

all_subnets = concat(var.public_subnets, var.private_subnets)

keys() and values()

Extract keys or values from a map:

tag_keys   = keys(var.tags)     # ["Environment", "Name", "Team"]
tag_values = values(var.tags)   # ["dev", "web-server", "backend"]

flatten()

Flattens nested lists into a single list:

all_cidrs = flatten([var.public_cidrs, var.private_cidrs])

lookup()

Look up a key in a map with a default fallback:

instance_type = lookup(var.instance_types, var.environment, "t3.micro")
# If var.environment isn't in the map, returns "t3.micro"

What’s Next?

You can now work with collections of values. Next, let’s learn about for expressions — a powerful way to transform and filter collections.


← String Interpolation & Types For Expressions →