What are some commonly used built-in Terraform functions, and how do you discover/test them?
Quick Answer
Terraform ships a large standard library of pure functions, grouped roughly by purpose: string functions (`format`, `join`, `split`, `replace`, `lower`/`upper`), collection functions (`merge`, `concat`, `flatten`, `distinct`, `lookup`, `contains`), numeric functions (`min`, `max`, `ceil`), encoding functions (`jsonencode`/`jsondecode`, `base64encode`, `yamlencode`), and filesystem functions (`file`, `fileexists`, `templatefile`). Note that Terraform has **no way to define custom functions** in HCL itself — you compose the built-ins to get the behavior you need. `terraform console` is the standard way to interactively try a function against real values before committing it to configuration, e.g. running `merge({a=1}, {b=2})` directly to confirm the exact output shape before relying on it inside a resource block.
Detailed Answer
HCL is deliberately not a general-purpose programming language — there's no way to define your own function. Instead, Terraform ships a broad standard library of built-in functions, and real configurations lean on composing them.
The major categories
String functions
format("web-%02d", 3) # "web-03"
join("-", ["a", "b", "c"]) # "a-b-c"
split(",", "a,b,c") # ["a", "b", "c"]
replace("hello world", " ", "-") # "hello-world"
lower("HELLO") # "hello"
Collection functions
merge({a = 1}, {b = 2}) # {a = 1, b = 2}
concat(["a"], ["b", "c"]) # ["a", "b", "c"]
flatten([["a", "b"], ["c"]]) # ["a", "b", "c"]
distinct(["a", "a", "b"]) # ["a", "b"]
lookup({env = "prod"}, "env", "dev") # "prod" (with a fallback default)
contains(["a", "b"], "a") # true
Numeric functions
max(1, 5, 3) # 5
min(1, 5, 3) # 1
ceil(4.1) # 5
Encoding functions
jsonencode({name = "web"}) # '{"name":"web"}'
jsondecode("{\"a\":1}") # {a = 1}
base64encode("hello")
yamlencode({name = "web"})
Filesystem functions
file("${path.module}/policy.json")
fileexists("${path.module}/optional.json")
templatefile("${path.module}/script.sh.tpl", { name = "web" })
Discovering and testing functions
terraform console is the standard way to try a function before committing to it in configuration:
$ terraform console
> merge({a = 1}, {b = 2})
{
"a" = 1
"b" = 2
}
> cidrsubnet("10.0.0.0/16", 8, 2)
"10.0.2.0/24"
This lets you confirm the exact output shape/type of an unfamiliar function against real values, interactively, without wiring it into a resource and running a full plan.
The key constraint to remember
There is no way to write a custom function in HCL. If the built-in library doesn't have exactly what you need, the standard approaches are: compose several built-ins together (a for expression combined with format, say), fall back to a local-exec provisioner calling an external script (rarely ideal, per the earlier provisioners discussion), or use Terraform's external data source / a purpose-built provider to shell out to real code. This is one of the clearest trade-offs of choosing a purpose-built declarative language over a general-purpose one like Pulumi's approach.