DevOpsLesson
DevOpsLesson

Free, comprehensive DevOps tutorials and learning roadmaps. Master Docker, Kubernetes, CI/CD, and more.

Stay Updated

Get notified about new tutorials and features.

Tutorials

  • What is DevOps?
  • Docker Tutorial
  • Terraform Tutorial
  • CI/CD Pipeline
  • All Tutorials

Roadmaps

  • DevOps Engineer
  • Cloud Engineer
  • SRE Path
  • All Roadmaps

Company

  • About Us
  • Blog
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 DevOpsLesson. All rights reserved.

DOCKERKUBERNETESTERRAFORMAWSCI/CDLINUXGITDEVOPS ROADMAPCLOUD ROADMAPSRE ROADMAPGIT CHEATSHEETDOCKER CHEATSHEETK8S CHEATSHEETTF CHEATSHEETLINUX CHEATSHEETDOCKERFILE LINTERYAML VALIDATORCRON PARSERREGEX TESTER

Terraform Tutorial

Introduction to Terraform
Installing Terraform
The Terraform Core Workflow
Terraform Variables and Outputs
Terraform State and Backends
Terraform Modules
Terraform Data Sources
Terraform Count and for_each
Terraform Expressions and Functions
Terraform Dynamic Blocks
Terraform Workspaces
Terraform with AWS
Terraform Provisioners
Terraform CI/CD Pipeline
Terraform Security

Terraform Collection Functions

PreviousPrev
Next

Learn Terraform list, map, set, and type-conversion functions, plus for expressions and transformation patterns for dynamic infrastructure code.

Why Collection Functions Matter

As soon as your Terraform configuration moves beyond a few hardcoded resources, you start working with collections of values rather than isolated strings.

Typical examples include:

  • a list of subnet CIDR blocks
  • a map of environment settings
  • a set of allowed regions
  • a list of bucket definitions
  • merged tags from multiple sources

Terraform collection functions help you shape that data into the exact form your resources, modules, and outputs need. They are especially important because cloud infrastructure is often repetitive but not perfectly uniform. You may need to combine lists, remove duplicates, merge maps, convert input types, or build a new collection dynamically from an old one.

Once you understand these functions, Terraform starts to feel far more expressive. Instead of repeating logic manually, you can transform data declaratively and keep your configuration compact.

A useful mental model is that collection functions sit between raw input and final resource arguments. Variables, module inputs, and data sources often provide values in a shape that is convenient for humans but not ideal for direct use in resources. Collection functions help you clean, combine, filter, and restructure that data so the rest of the configuration stays easier to read.

List Functions

Lists are ordered collections. Terraform includes several functions that help you combine, filter, inspect, and reorganize them.

concat()

concat() combines multiple lists into one list.

concat(["subnet-a"], ["subnet-b", "subnet-c"])

Result:

["subnet-a", "subnet-b", "subnet-c"]

Use cases:

  • combine default and custom lists
  • merge subnet groups
  • build a final list from several sources

Example:

locals {
  all_cidrs = concat(var.default_cidrs, var.extra_cidrs)
}

flatten()

flatten() converts a nested list into a single-level list.

flatten([["a", "b"], ["c"], ["d", "e"]])

Result:

["a", "b", "c", "d", "e"]

This is very useful when different expressions each produce a list and you want one final list.

distinct()

distinct() removes duplicate elements while preserving the first occurrence order.

distinct(["dev", "prod", "dev", "staging"])

Result:

["dev", "prod", "staging"]

This is helpful when inputs may overlap and you want clean results.

slice()

slice(list, start, end) returns a portion of a list.

slice(["a", "b", "c", "d"], 1, 3)

Result:

["b", "c"]

Common use cases:

  • choose the first two availability zones
  • trim an input list
  • test subsets of values

reverse()

reverse() returns the elements in the opposite order.

reverse(["a", "b", "c"])

Result:

["c", "b", "a"]

This is less common than concat() or flatten(), but it can be useful in selection logic.

sort()

sort() returns a sorted version of a list of strings.

sort(["prod", "dev", "staging"])

Result:

["dev", "prod", "staging"]

This helps when you want predictable ordering, especially before turning values into outputs or iterating for human-readable results.

length()

length() works on strings and collections.

length(["a", "b", "c"])

Result:

3

This is essential for:

  • driving count
  • validations
  • conditional logic

In practice, list functions are often used together. For example, you might concat() two subnet lists, distinct() the result to remove duplicates, and then sort() it to produce predictable ordering for outputs or iteration.

Map Functions

Maps store key-value pairs. They are ideal for named configuration.

merge()

merge() combines maps into one map.

merge(
  { Environment = "dev" },
  { Project = "shop" },
  { ManagedBy = "Terraform" }
)

Result:

{
  Environment = "dev"
  Project     = "shop"
  ManagedBy   = "Terraform"
}

This is very common for tags.

Example:

locals {
  common_tags = merge(var.default_tags, {
    Environment = var.environment
  })
}

If duplicate keys exist, later maps win.

lookup()

lookup(map, key, default) fetches a value from a map and optionally returns a fallback.

lookup(var.instance_types, var.environment, "t3.micro")

This is useful when not every key is guaranteed to exist.

keys()

keys() returns a list of map keys.

keys({ dev = "t3.micro", prod = "t3.medium" })

Result:

["dev", "prod"]

Useful when you want to iterate over the names in a map or inspect which items exist.

values()

values() returns the map values.

values({ dev = "t3.micro", prod = "t3.medium" })

Result:

["t3.micro", "t3.medium"]

This is helpful when only the values matter for a downstream expression.

zipmap()

zipmap(keys, values) constructs a map by pairing elements from two lists.

zipmap(["dev", "prod"], ["t3.micro", "t3.medium"])

Result:

{
  dev  = "t3.micro"
  prod = "t3.medium"
}

This is useful when data arrives in parallel lists and you want a more meaningful map structure.

Set Functions

Sets are unordered collections of unique values. They are useful with for_each, membership logic, and deduplication.

toset(), Set Conversion

toset() converts another collection into a set.

toset(["dev", "dev", "prod"])

Result:

["dev", "prod"]

This is commonly used with for_each:

for_each = toset(var.environments)

setintersection()

Returns values present in both sets.

setintersection(toset(["dev", "prod"]), toset(["prod", "stage"]))

Result:

["prod"]

Useful for identifying overlap between allowed values and requested values.

setunion()

Returns all unique values across both sets.

setunion(toset(["a", "b"]), toset(["b", "c"]))

Result:

["a", "b", "c"]

setsubtract()

Returns values from the first set that are not in the second.

setsubtract(toset(["dev", "stage", "prod"]), toset(["stage"]))

Result:

["dev", "prod"]

Useful for exclusions and policy checks.

Type Conversion Functions

Terraform often needs values in a specific type. Type-conversion functions help you normalize data for resources and modules.

tolist()

Converts a value into a list where possible.

tolist(toset(["a", "b"]))

Use this when a resource or expression expects list behavior.

tomap()

Converts a value into a map where possible.

This is helpful when you want consistent map semantics for merging or lookups.

toset(), Type Conversion

Converts a collection to a set.

This is common for deduplication and for_each iteration.

tostring()

Converts a value into a string.

tostring(42)

Result:

"42"

Useful for tags, names, or outputs where a string is required.

tonumber()

Converts a value into a number.

tonumber("8080")

Result:

8080

Useful when input arrives as text but arithmetic or numeric provider fields require a number.

for Expressions

One of the most powerful collection features in Terraform is the for expression.

A basic list transformation looks like this:

[for x in var.list : x if condition]

This means:

  • iterate over each item in var.list
  • emit x for matching items
  • optionally filter with if

Example: filtering environments

[for env in var.environments : env if env != "dev"]

This returns all environments except dev.

Example: building a new list

[for cidr in var.subnet_cidrs : "subnet-${cidr}"]

Example: building a map

{ for env in var.environments : env => upper(env) }

That returns a map where each environment is keyed to its uppercase version.

Dynamic Expressions for Complex Transformations

Real Terraform code often combines multiple functions and for expressions.

Example:

locals {
  normalized_envs = distinct(sort([for env in var.environments : lower(trimspace(env))]))
}

This one expression:

  • trims whitespace
  • converts values to lowercase
  • sorts them
  • removes duplicates

That is a good example of Terraform data transformation in practice.

Practical tag-merging example

locals {
  common_tags = merge(
    var.default_tags,
    {
      Environment = var.environment
      Project     = var.project_name
    }
  )
}

Practical object transformation example

locals {
  bucket_map = {
    for bucket in var.buckets :
    bucket.name => {
      acl        = bucket.acl
      versioning = bucket.versioning
    }
  }
}

This is the kind of structure that can then feed for_each cleanly.

A Realistic Example: Networking Inputs

Suppose you receive subnet CIDRs from different sources and want a clean, consistent output.

variable "default_subnet_cidrs" {
  type = list(string)
}

variable "extra_subnet_cidrs" {
  type = list(string)
}

locals {
  combined_subnets   = concat(var.default_subnet_cidrs, var.extra_subnet_cidrs)
  distinct_subnets   = distinct(local.combined_subnets)
  sorted_subnets     = sort(local.distinct_subnets)
  selected_subnets   = slice(local.sorted_subnets, 0, 2)
  subnet_name_map    = zipmap(local.selected_subnets, ["app", "data"])
}

This example shows how collection functions help turn raw input into well-structured, intentional values.

Best Practices for Collection Transformations

1. Prefer clarity over compression

A very long one-line expression may be technically correct but difficult to maintain. Break complex logic into multiple local values when needed.

2. Use maps for named configuration

Maps usually model real infrastructure identity better than parallel lists.

3. Normalize collections before iteration

Deduplicating, sorting, or trimming inputs early makes later resource logic simpler.

4. Be careful with set ordering assumptions

Sets are unordered. If order matters, convert intentionally and do not depend on set position.

5. Use for expressions to express intent

for expressions are great when the goal is transformation, filtering, or reshaping data for later use.

Common Beginner Mistakes

Mistake 1: Keeping everything in parallel lists

Parallel lists are fragile. If named configuration matters, maps are often a better structure.

Mistake 2: Forgetting type expectations

Some functions and meta-arguments expect specific types. Conversions like toset() and tomap() help, but you must be intentional.

Mistake 3: Assuming sets preserve order

They do not. If order matters for output or selection, use lists deliberately.

Mistake 4: Writing transformations inline everywhere

If the same logic is reused, move it into locals.

Final Thoughts

Terraform collection functions are the tools that let you treat infrastructure inputs as structured data instead of static text. Once you can combine, merge, deduplicate, filter, and reshape collections, your configurations become far more reusable and far less repetitive.

A strong beginner workflow is:

  • collect inputs with variables or data sources
  • normalize them with functions and locals
  • transform them with for expressions
  • feed the clean result into resources, modules, and outputs

That pattern appears again and again in well-designed Terraform code.


Knowledge Check

Exercise

Question 1: concat()

What does Terraform's concat() function do?

Exercise

Question 2: merge()

Which Terraform function is commonly used to combine multiple tag maps into one?

Exercise

Question 3: for Expressions

What does the expression [for env in var.environments : env if env != "dev"] return?

PreviousPrev
Next

Continue Learning

Terraform for_each

Learn how Terraform for_each works with maps, sets, and transformed collections, how to reference named instances, and when for_each is better than count.

12 min read·Easy

Terraform Expressions and Functions

Get a quick overview of Terraform expressions and built-in functions before diving into string operations and collection transformations.

5 min read·Easy

Terraform String Functions

Learn Terraform string interpolation, formatting, replacements, regex helpers, templatefile, conditionals, and other string-oriented expressions used in real infrastructure code.

10 min read·Easy

Explore Related Topics

AW

AWS Tutorials

Provision AWS infrastructure with Terraform

CI

CI/CD Tutorials

Run terraform plan/apply in CI pipelines

Try the Tool

YAML Validator

Validate Terraform and Kubernetes YAML configs before applying.

On This Page

Why Collection Functions MatterList Functions`concat()``flatten()``distinct()``slice()``reverse()``sort()``length()`Map Functions`merge()``lookup()``keys()``values()``zipmap()`Set Functions`toset()`, Set Conversion`setintersection()``setunion()``setsubtract()`Type Conversion Functions`tolist()``tomap()``toset()`, Type Conversion`tostring()``tonumber()``for` ExpressionsExample: filtering environmentsExample: building a new listExample: building a mapDynamic Expressions for Complex TransformationsPractical tag-merging examplePractical object transformation exampleA Realistic Example: Networking InputsBest Practices for Collection Transformations1. Prefer clarity over compression2. Use maps for named configuration3. Normalize collections before iteration4. Be careful with set ordering assumptions5. Use `for` expressions to express intentCommon Beginner MistakesMistake 1: Keeping everything in parallel listsMistake 2: Forgetting type expectationsMistake 3: Assuming sets preserve orderMistake 4: Writing transformations inline everywhereFinal ThoughtsKnowledge Check