Terraform Functions Built In Helpers for Data Transformation

Terraform includes over 100 built-in functions that let you transform, combine, and manipulate data inside your configuration — without writing external scripts. Functions make your code smarter, more dynamic, and less repetitive. This topic covers the most useful function categories with practical examples.

How Functions Work in Terraform

Functions in Terraform look like functions in any programming language: a name, parentheses, and arguments. They return a computed value that you use anywhere an expression is valid.

# Syntax: function_name(argument1, argument2, ...)
length("hello")          # returns 5
upper("hello")           # returns "HELLO"
max(3, 5, 1)             # returns 5

You can test any function interactively using terraform console:

$ terraform console
> upper("terraform")
"TERRAFORM"
> length(["a", "b", "c"])
3

terraform console opens an interactive shell where you try functions and expressions without touching any real infrastructure — great for learning and debugging.

String Functions

FunctionExampleResult
upper(s)upper("hello")"HELLO"
lower(s)lower("HELLO")"hello"
replace(s, old, new)replace("hello world", " ", "-")"hello-world"
trimspace(s)trimspace(" hello ")"hello"
substr(s, offset, length)substr("hello", 0, 3)"hel"
format(spec, ...)format("app-%03d", 5)"app-005"

Practical Use: Enforcing Lowercase Names

locals {
  bucket_name = lower(replace("My App Bucket ${var.environment}", " ", "-"))
  # "my-app-bucket-prod" — S3 bucket names must be lowercase
}

Collection Functions

FunctionWhat It Does
length(list)Returns the number of items in a list, map, or string
merge(map1, map2)Combines two or more maps into one
concat(list1, list2)Joins two or more lists into one list
flatten(list)Converts a nested list into a flat list
distinct(list)Removes duplicate values from a list
toset(list)Converts a list to a set (removes duplicates, unordered)
keys(map)Returns a sorted list of keys from a map
values(map)Returns a list of values from a map
lookup(map, key, default)Returns a map value for a key, or a default if not found
contains(list, value)Returns true if a list contains the value

Practical Use: Merging Base Tags with Resource Tags

locals {
  base_tags = { Environment = "prod", ManagedBy = "Terraform" }
}

resource "aws_s3_bucket" "data" {
  bucket = "my-data-bucket"
  tags   = merge(local.base_tags, { Name = "data-bucket", Purpose = "analytics" })
  # Result: { Environment="prod", ManagedBy="Terraform", Name="data-bucket", Purpose="analytics" }
}

Numeric Functions

max(10, 20, 5)     # 20
min(10, 20, 5)     # 5
abs(-7)            # 7
ceil(1.2)          # 2
floor(1.9)         # 1

Encoding Functions

FunctionUse Case
base64encode(string)Encode a string to Base64 (required for some API values)
base64decode(string)Decode a Base64 string
jsonencode(value)Convert a Terraform value to a JSON string
jsondecode(string)Parse a JSON string into a Terraform value
yamlencode(value)Encode a value as YAML

Practical Use: Inline IAM Policy with jsonencode

resource "aws_iam_role_policy" "s3_read" {
  name = "s3-read-policy"
  role = aws_iam_role.app.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect   = "Allow"
        Action   = ["s3:GetObject", "s3:ListBucket"]
        Resource = "*"
      }
    ]
  })
}

jsonencode converts native HCL maps and lists to JSON strings — making IAM policies readable and avoiding error-prone manual JSON escaping.

IP and CIDR Functions

# Split a CIDR into subnets
cidrsubnet("10.0.0.0/16", 8, 1)   # "10.0.1.0/24"
cidrsubnet("10.0.0.0/16", 8, 2)   # "10.0.2.0/24"
cidrsubnet("10.0.0.0/16", 8, 3)   # "10.0.3.0/24"

Use cidrsubnet to dynamically calculate subnet CIDR blocks from a parent VPC CIDR — no manual subnet math required.

Key Points

  • Terraform has 100+ built-in functions for transforming strings, lists, maps, numbers, and more.
  • Test functions interactively with terraform console before using them in configuration.
  • Use merge() to combine tag maps; use jsonencode() to write inline JSON policies cleanly.
  • Use cidrsubnet() to compute subnet CIDRs dynamically from a parent VPC CIDR block.
  • Functions run at plan time — their results are calculated before any infrastructure is created.

Leave a Comment