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.
format and joinUse 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"
}
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() 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
}
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() 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"]
}
zipmap for key-value transformationszipmap() 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" }
}
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"
}
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"]
}
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"
}
if() for ternary expressionsif(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")
}
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
}
lookup and coalescecoalesce() 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"
)
}
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")
}
)
)
}
lookup() with missing keys returns null, not a default. lookup(config, "database", "host") # returns null if "database" or "host" missing
Use coalesce() to provide fallbacks.
split() returns [] on empty input, not null.map() and filter() create new lists, but are lazy—they do not evaluate until used.merge() overwrites keys in order, but does not deep merge: nested maps are replaced, not merged. merge(
{ db = { host = "prod" } },
{ db = { port = 5432 } }
)
# Result: { db = { port = 5432 } } — host is lost
format() applies to all arguments, including nested functions. format("Instance %s in %s", var.instance, format("%s-%s", var.region, var.env))
# Result: "Instance web-01 in us-west-1-prod"
join() expects a list, not a tuple or map; passing a map results in a list of key-value pairs. join(",", { a = 1, b = 2 }) # ["a=1", "b=2"]
Terraform throws errors when evaluating expressions, especially in locals, outputs, and variables.
data blocks can fail silently if a data source returns null. 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 expressions fail if the input is not a list or map. for k, v in { a = 1 } : k # Works
for k, v in "invalid" : k # Error: "invalid" is not a map or list
with expressions require consistent keys across all maps. 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.
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.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy