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
| Function | Example | Result |
|---|---|---|
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
| Function | What 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
| Function | Use 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 consolebefore using them in configuration. - Use
merge()to combine tag maps; usejsonencode()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.
