Terraform Functions Reference

Comprehensive guide to terraform functions reference covering architecture, implementation, testing, and operational patterns for production engineering teams.

Terraform Functions Reference provides a curated, precise, and immediately actionable guide to the built-in and user-defined functions available in Terraform’s configuration language (HCL). This reference is essential when writing complex, reusable, and maintainable infrastructure-as-code (IaC) configurations, particularly when transforming, validating, or combining values across resources, modules, and data sources. It matters most when you need to dynamically compute values, conditionally apply logic, or abstract common patterns across multiple environments.

Working with Strings

Concatenate strings with format and join

Use format() to create formatted strings from multiple values, with placeholders %s, %d, %f, etc.

locals {
  cluster_name = format("prod-%s-%s", var.region, var.environment)
  log_path     = format("/var/log/%s/%s/%s", var.app, var.version, var.env)
}

The join() function combines a list of strings into a single string using a delimiter.

locals {
  tags = {
    Environment = "prod"
    Project     = "web"
    Region        = "us-west-1"
  }

  tag_string = join(",", [for k, v in local.tags : "${k}=${v}"])
  # Result: "Environment=prod,Project=web,Region=us-west-1"
}

Transform case and extract substrings

Use lower(), upper(), title(), and replace() for case manipulation.

locals {
  name = "my-app-service"
  lower_name  = lower(local.name)  # "my-app-service"
  title_name  = title(local.name)  # "My-App-Service"
  slug_name   = replace(local.name, "-", "_")  # "my_app_service"
}

substr() extracts a substring from a string using a start index and length.

locals {
  hostname = "web-prod-01"
  short_name = substr(local.hostname, 0, 8)  # "web-prod"
}

Split and filter strings

split() divides a string into a list using a delimiter.

locals {
  regions = split(",", "us-east-1,us-west-2,eu-central-1")
  # Result: ["us-east-1", "us-west-2", "eu-central-1"]
}

Filter strings with length() and contains().

locals {
  config = "prod:web:api"
  has_api = contains(split(":", local.config), "api")  # true
  config_length = length(split(":", local.config))     # 3
}

Working with Lists and Tuples

Build and transform lists

list() creates a new list from values.

locals {
  servers = list("web-01", "web-02", "api-01")
}

Use flatten() to merge nested lists.

locals {
  layers = [
    ["web", "api"],
    ["db", "cache"],
    ["ingest", "batch"]
  ]

  all_layers = flatten(local.layers)  # ["web", "api", "db", "cache", "ingest", "batch"]
}

merge() combines multiple maps into one, with later maps overwriting earlier ones.

locals {
  default = {
    memory = "4GB"
    cpu    = 2
  }

  overrides = {
    memory = "8GB"
    disk   = "50GB"
  }

  config = merge(local.default, local.overrides)
  # Result: { memory = "8GB", cpu = 2, disk = "50GB" }
}

Filter and map over lists

filter() returns a list of elements satisfying a condition.

locals {
  instances = [
    { name = "web-01", type = "t3.small" },
    { name = "web-02", type = "t3.medium" },
    { name = "api-01", type = "t3.large" },
    { name = "db-01", type = "r5.xlarge" }
  ]

  small_instances = filter(
    local.instances,
    each.type == "t3.small"
  )
}

map() applies a function to each element of a list.

locals {
  names = map(
    local.instances,
    each.name
  )
  # Result: ["web-01", "web-02", "api-01", "db-01"]
}

Use zipmap for key-value transformations

zipmap() pairs two lists into a map.

locals {
  keys   = ["name", "region", "env"]
  values = ["web-app", "us-west-1", "prod"]

  config = zipmap(local.keys, local.values)
  # Result: { name = "web-app", region = "us-west-1", env = "prod" }
}

Working with Maps and Objects

Extract, merge, and transform maps

keys() returns all keys in a map.

locals {
  db_config = {
    host = "db.example.com"
    port = 5432
    user = "postgres"
    password = "secret"
  }

  db_keys = keys(local.db_config)  # ["host", "port", "user", "password"]
}

values() returns all values.

locals {
  db_values = values(local.db_config)  # ["db.example.com", 5432, "postgres", "secret"]
}

merge() combines multiple maps, resolving conflicts by overwriting.

locals {
  base = { debug = true, log_level = "info" }
  env  = { log_level = "debug", timeout = 30 }

  final_config = merge(local.base, local.env)
  # Result: { debug = true, log_level = "debug", timeout = 30 }
}

Use lookup() to safely extract values from nested maps.

locals {
  config = {
    app = {
      env = "prod"
      version = "1.2.0"
    }
    db = {
      host = "rds-prod.example.com"
      port = 5432
    }
  }

  app_env = lookup(local.config, "app", "env")  # "prod"
  db_host = lookup(local.config, "db", "host")  # "rds-prod.example.com"
  unknown = lookup(local.config, "cache", "host", "default")  # "default"
}

Working with Numbers and Dates

Perform arithmetic and type conversion

Terraform supports standard arithmetic: +, -, *, /, %, **.

locals {
  cost_per_hour = 0.065
  hours = 730
  total_cost = local.cost_per_hour * local.hours  # 47.45
}

Convert types with tonumber(), tobool(), toset(), tolist().

locals {
  raw_data = "42"
  count = tonumber(local.raw_data)  # 42
  active = tobool("true")  # true
  unique_ids = toset(["a", "b", "a", "c"])  # ["a", "b", "c"]
}

Format and manipulate dates

timestamp() returns the current timestamp in RFC3339 format.

locals {
  now = timestamp()  # "2023-04-05T12:34:56Z"
}

timeadd() adds a duration to a timestamp.

locals {
  start_time = "2023-04-05T12:34:56Z"
  end_time = timeadd(local.start_time, "1h30m")  # "2023-04-05T14:04:56Z"
}

timeopen() and timediff() compute durations.

locals {
  start = "2023-04-05T12:00:00Z"
  end   = "2023-04-05T14:30:00Z"

  duration = timediff(local.start, local.end)  # "2h30m"
}

Use formatdate() to render timestamps in custom formats.

locals {
  formatted = formatdate("2023-04-05T12:34:56Z", "YYYY-MM-DD HH:MM:SS")
  # Result: "2023-04-05 12:34:56"
}

Conditionals and Logic

Use if() for ternary expressions

if(condition, true_value, false_value) evaluates a condition and returns one of two values.

locals {
  is_production = var.environment == "prod"
  instance_type = if(local.is_production, "c5.2xlarge", "t3.medium")
}

Combine conditions with all() and any()

all() checks that all elements in a list are true.

locals {
  services = [true, true, false, true]
  all_up = all(local.services)  # false
}

any() returns true if at least one element is true.

locals {
  any_ready = any(local.services)  # true
}

Nest conditionals with lookup and coalesce

coalesce() returns the first non-null value from a list.

locals {
  db_host = coalesce(
    var.db_host,
    lookup(var.config, "database", "host"),
    "localhost"
  )
  # First non-null value among the three options
}

Use lookup() with coalesce() for fallback logic.

locals {
  config = {
    app = {
      log_level = "info"
    }
  }

  log_level = coalesce(
    lookup(local.config, "app", "log_level"),
    lookup(local.config, "app", "level"),
    "debug"
  )
}

Advanced Patterns and Failure Modes

Function composition and higher-order patterns

Terraform functions can be composed to form complex expressions.

locals {
  tags = {
    Name        = "web-server"
    Environment = "prod"
  }

  tags_json = jsonencode(
    merge(
      local.tags,
      {
        CreatedAt = formatdate(timestamp(), "YYYY-MM-DD")
      }
    )
  )
}

Silent failures and common pitfalls

  lookup(config, "database", "host")  # returns null if "database" or "host" missing

Use coalesce() to provide fallbacks.

  merge(
    { db = { host = "prod" } },
    { db = { port = 5432 } }
  )
  # Result: { db = { port = 5432 } } — host is lost
  format("Instance %s in %s", var.instance, format("%s-%s", var.region, var.env))
  # Result: "Instance web-01 in us-west-1-prod"
  join(",", { a = 1, b = 2 })  # ["a=1", "b=2"]

Error handling in expressions

Terraform throws errors when evaluating expressions, especially in locals, outputs, and variables.

  data "aws_ami" "latest" {
    name_regex = "amzn2-ami-hvm-*-x86_64-gp2"
    owners       = ["amazon"]
  }

  # If no AMI matches, data.aws_ami.latest.id is null, causing error in next block
  for k, v in { a = 1 } : k  # Works
  for k, v in "invalid" : k  # Error: "invalid" is not a map or list
  with(
    { a = 1, b = 2 },
    { a = 3, c = 4 }
  )
  # Result: { a = 3, b = 2, c = 4 }
  # But if keys don’t align, error on missing keys.

Common idiom: building dynamic resource names

resource "aws_s3_bucket" "main" {
  bucket = format("%s-%s-%s", var.project, var.environment, var.region)
  tags = merge(
    {
      Name = format("%s-%s", var.project, var.environment)
    },
    var.tags
  )
}

This pattern is the backbone of consistent, predictable infrastructure across environments.

Terraform Functions Reference is not a catalog of functions; it is a guide to using them effectively in real-world configurations. The interplay of functions, expressions, and data types enables powerful abstractions. Mastering this reference ensures that your Terraform code is not just declarative, but also expressive, robust, and maintainable.

This page was rewritten on 14 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.