Home
Insights
Terraform Functions: Complete Reference with Practical Examples

Terraform Functions: Complete Reference with Practical Examples

with special guest
Mitchell
Hashimoto
Mitchell Hashimoto headshot

Terraform does more than just provision infrastructure. It gives you a powerful set of built-in functions you can use inside your configuration to transform data, format strings, loop over collections, encode values, and much more.

If you have ever written Terraform and found yourself repeating values, hard-coding logic, or wishing you could manipulate a list before passing it to a resource β€” functions are the answer.

This guide covers every major category of Terraform functions, with real examples you can drop straight into your codebase.

What Are Terraform Functions?

Terraform functions are built-in expressions you can call inside your .tf files to compute or transform values. They are similar to functions in any programming language β€” you pass in one or more arguments, and they return a result.

You use them inside ${} expressions or directly in resource arguments. Here is a simple example using the upper function:

Simple example showing how to use a variable and an output with a function:



variable "env" {
default = "production"
}

output "env_label" {
value = upper(var.env) # Returns "PRODUCTION"
}

This demonstrates using the upper() function to convert a variable value to uppercase in the output.

Terraform functions are evaluated at plan time, not at runtime. That means the result is computed before any infrastructure is created β€” making your configurations predictable and safe to review.

String Functions

String functions let you manipulate, format, and transform text values. These are among the most commonly used functions in real Terraform configurations.

Function What It Does Example
upper(string) Converts a string to uppercase upper("hello") β†’ "HELLO"
lower(string) Converts a string to lowercase lower("WORLD") β†’ "world"
trimspace(string) Removes leading and trailing whitespace trimspace(" hi ") β†’ "hi"
trim(string, chars) Removes specific characters from both ends trim("--env--", "-") β†’ "env"
replace(string, search, replace) Replaces occurrences of a substring replace("a-b-c", "-", "_") β†’ "a_b_c"
split(sep, string) Splits a string into a list split(",", "a,b,c") β†’ ["a","b","c"]
join(sep, list) Joins a list into a single string join("-", ["us","east","1"]) β†’ "us-east-1"
format(template, args...) Formats a string using a template format("app-%s-%d", "web", 1) β†’ "app-web-1"
startswith(string, prefix) Returns true if string starts with prefix startswith("prod-api", "prod") β†’ true
endswith(string, suffix) Returns true if string ends with suffix endswith("main.tf", ".tf") β†’ true
substr(string, offset, length) Returns a substring substr("terraform", 0, 5) β†’ "terra"
strlen(string) Returns the number of characters in a string strlen("hello") β†’ 5

Practical String Example: Building Consistent Resource Names

One of the most common uses of string functions is building standardised resource names from input variables:

Example showing how to create a consistent resource naming pattern using variables, format(), and lower():



variable "project" { default = "payments" }
variable "env" { default = "prod" }
variable "region" { default = "us-east-1" }

locals {
name_prefix = lower(format("%s-%s-%s", var.project, var.env, var.region))
# Result: "payments-prod-us-east-1"
}

resource "aws_s3_bucket" "data" {
bucket = "${local.name_prefix}-data"
# Result: "payments-prod-us-east-1-data"
}

This demonstrates combining project, environment, and region into a **lowercase, hyphen-separated prefix** for consistent S3 bucket naming.

Numeric Functions

Numeric functions let you perform arithmetic operations and comparisons on number values.

Function What It Does Example
abs(number) Returns the absolute value of a number abs(-5) β†’ 5
ceil(number) Rounds up to the nearest whole number ceil(1.2) β†’ 2
floor(number) Rounds down to the nearest whole number floor(1.9) β†’ 1
max(numbers...) Returns the largest number max(3, 7, 2) β†’ 7
min(numbers...) Returns the smallest number min(3, 7, 2) β†’ 2
pow(base, exponent) Raises base to the power of exponent pow(2, 8) β†’ 256
signum(number) Returns -1, 0, or 1 based on sign signum(-4) β†’ -1
log(number, base) Returns the logarithm of a number log(100, 10) β†’ 2
parseint(string, base) Parses a string as an integer parseint("FF", 16) β†’ 255

Practical Numeric Example: Calculating Instance Counts

Example showing how to calculate dynamic instance count using ceil() to ensure all team members are covered:



variable "team_size" { default = 12 }

locals {
# Always round up so no team member is left without a node
node_count = ceil(var.team_size / 4)
# Result: 3
}

resource "aws_instance" "worker" {
count = local.node_count
# ...
}

This demonstrates using ceil() to calculate the number of instances dynamically, ensuring each team member has a dedicated node.

Collection Functions

Collection functions are some of the most powerful in Terraform. They let you work with lists, maps, and sets β€” filtering, merging, transforming, and inspecting them.

Function What It Does Example
length(collection) Returns the number of elements length(["a","b","c"]) β†’ 3
contains(list, value) Returns true if value is in the list contains(["dev","prod"], "prod") β†’ true
distinct(list) Returns a list with duplicates removed distinct(["a","b","a"]) β†’ ["a","b"]
flatten(list) Flattens a nested list into a single list flatten([[1,2],[3]]) β†’ [1,2,3]
concat(lists...) Combines multiple lists into one concat([1,2],[3,4]) β†’ [1,2,3,4]
merge(maps...) Merges multiple maps, later keys win merge({a=1},{a=2,b=3}) β†’ {a=2,b=3}
keys(map) Returns a sorted list of map keys keys({b=2,a=1}) β†’ ["a","b"]
values(map) Returns a list of map values values({a=1,b=2}) β†’ [1,2]
lookup(map, key, default) Looks up a key with a default fallback lookup({a=1}, "b", 0) β†’ 0
slice(list, start, end) Returns a subset of a list slice([1,2,3,4], 1, 3) β†’ [2,3]
sort(list) Sorts a list of strings alphabetically sort(["c","a","b"]) β†’ ["a","b","c"]
reverse(list) Reverses the order of a list reverse([1,2,3]) β†’ [3,2,1]
toset(list) Converts a list to a set (removes duplicates) toset(["a","a","b"]) β†’ set("a","b")
tolist(set) Converts a set to a list tolist(toset([1,1,2])) β†’ [1,2]
tomap(object) Converts an object to a map tomap({a=1,b=2})
zipmap(keys, values) Creates a map from separate key and value lists zipmap(["a","b"],[1,2]) β†’ {a=1,b=2}

Practical Collection Example: Merging Environment Tags

A very common pattern is merging a base set of tags with environment-specific ones:

Example showing how to define base and environment tags using locals and merge() to apply consistent tags to AWS resources:



locals {
base_tags = {
managed_by = "terraform"
team = "platform"
}

env_tags = {
environment = var.env
cost_centre = var.cost_centre
}

all_tags = merge(local.base_tags, local.env_tags)
}

resource "aws_instance" "app" {
# ...
tags = local.all_tags
}

This demonstrates creating reusable tag sets for AWS resources, combining base tags and environment-specific tags into a single all_tags map for consistent tagging across your infrastructure.

Date and Time Functions

Terraform includes a small set of functions for working with timestamps β€” useful for generating unique resource names, setting expiry values, or tagging resources with creation dates.

Function What It Does Example
timestamp() Returns the current UTC timestamp as an RFC 3339 string timestamp() β†’ "2026-05-01T09:00:00Z"
timeadd(timestamp, duration) Adds a duration to a timestamp timeadd("2026-01-01T00:00:00Z", "24h")
timecmp(ts1, ts2) Compares two timestamps: returns -1, 0, or 1 timecmp(t1, t2)
formatdate(format, timestamp) Formats a timestamp into a readable string formatdate("YYYY-MM-DD", timestamp())
plantimestamp() Returns a constant timestamp fixed at plan time (Terraform 1.5+) plantimestamp()

Practical Date Example: Tagging Resources with a Creation Date

Example showing how to use formatdate() and timestamp() to create date-based S3 bucket names and tags:



locals {
created_date = formatdate("YYYY-MM-DD", timestamp())
}

resource "aws_s3_bucket" "archive" {
bucket = "logs-archive-${local.created_date}"
tags = {
created_on = local.created_date
}
}

This demonstrates creating dynamic S3 bucket names and tags based on the current date, making it easy to track when buckets were created.

Encoding Functions

Encoding functions let you convert data between different formats β€” essential when you need to pass structured data as strings, or work with base64-encoded secrets and certificates.

Function What It Does Example
base64encode(string) Encodes a string as base64 base64encode("hello") β†’ "aGVsbG8="
base64decode(string) Decodes a base64 string base64decode("aGVsbG8=") β†’ "hello"
jsonencode(value) Converts a value to a JSON string jsonencode({a=1}) β†’ "{\"a\":1}"
jsondecode(string) Parses a JSON string into a Terraform value jsondecode("{\"a\":1}") β†’ {a=1}
yamlencode(value) Converts a value to a YAML string yamlencode({key = "value"})
yamldecode(string) Parses a YAML string into a Terraform value yamldecode(file("config.yaml"))
urlencode(string) Encodes a string for use in a URL urlencode("hello world") β†’ "hello+world"
textencodebase64(string, encoding) Encodes a string to base64 using a specific charset textencodebase64(str, "UTF-16LE")
base64gzip(string) Compresses and encodes a string as base64 base64gzip(large_script)

Practical Encoding Example: Passing a JSON Policy to AWS IAM

Example showing how to use jsonencode() to define an IAM policy and attach it to a role:



locals {
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = ["s3:GetObject"]
Resource = "arn:aws:s3:::my-bucket/*"
}]
})
}

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

This demonstrates using jsonencode() to create a JSON IAM policy in Terraform and attach it to an existing IAM role for S3 read access.

Filesystem Functions

Filesystem functions let you read files from your local disk into your Terraform configuration. This is useful for loading scripts, certificates, policies, and other external content.

Function What It Does Example
file(path) Reads a file and returns its content as a string file("scripts/init.sh")
filebase64(path) Reads a file and returns its content as base64 filebase64("certs/ca.pem")
fileexists(path) Returns true if the file exists at the given path fileexists("override.tf")
fileset(path, pattern) Returns a set of file paths matching a glob pattern fileset("templates/", "*.json")
templatefile(path, vars) Renders a template file with variable substitutions templatefile("user_data.tpl", {env=var.env})
abspath(path) Converts a relative path to an absolute path abspath("./modules")
dirname(path) Returns the directory part of a path dirname("/etc/nginx/nginx.conf") β†’ "/etc/nginx"
basename(path) Returns the filename part of a path basename("/etc/nginx/nginx.conf") β†’ "nginx.conf"
pathexpand(path) Expands ~ to the user home directory pathexpand("~/.ssh/id_rsa")

Practical Filesystem Example: Loading User Data from a Template

Example showing how to use templatefile() to pass variables into a Linux user_data script for an EC2 instance:



# user_data.tpl
#!/bin/bash
echo "Environment: ${environment}"
echo "Region: ${region}"
apt-get update && apt-get install -y ${package}

# main.tf
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3.medium"

user_data = templatefile("user_data.tpl", {
environment = var.env
region = var.region
package = "nginx"
})
}

This demonstrates passing Terraform variables into a shell script using templatefile(), allowing dynamic configuration of EC2 instances at launch.

Type Conversion Functions

Terraform is a strongly typed language. Sometimes you need to convert a value from one type to another β€” for example, converting a number to a string so it can be used in a resource name, or converting a list to a set to remove duplicates.

Function What It Does Example
tostring(value) Converts a value to a string tostring(42) β†’ "42"
tonumber(value) Converts a value to a number tonumber("42") β†’ 42
tobool(value) Converts a value to a boolean tobool("true") β†’ true
tolist(value) Converts a set or tuple to a list tolist(toset([1,2,3]))
toset(value) Converts a list or tuple to a set toset(["a","b","a"]) β†’ set("a","b")
tomap(value) Converts an object to a map tomap({a=1, b=2})
can(expression) Returns true if an expression does not produce an error can(var.config.key)
try(expressions...) Returns the first expression that does not error try(var.opt, "default")
type(value) Returns the type of a value as a string (for debugging) type(var.input)

Practical Type Conversion Example: Safe Optional Variable Lookup

The try function is especially useful when working with optional or nested variables that might not always be set:

Example showing how to safely retrieve nested values from a configuration variable using try() with default fallbacks:



variable "config" {
type = any
default = {}
}

locals {
# Safely retrieve nested values with a fallback
log_level = try(var.config.logging.level, "info")
max_replicas = try(tonumber(var.config.replicas.max), 5)
}

This demonstrates using try() to avoid errors when accessing nested values and providing sensible defaults for logging and replicas.

Hash and Crypto Functions

Hash functions generate a fixed-length fingerprint of a value. They are often used to generate unique identifiers, detect changes, or create deterministic resource names based on content.

Function What It Does Example
md5(string) Returns the MD5 hash of a string md5("hello") β†’ "5d41402..."
sha1(string) Returns the SHA-1 hash of a string sha1("hello")
sha256(string) Returns the SHA-256 hash of a string sha256("hello")
sha512(string) Returns the SHA-512 hash of a string sha512("hello")
bcrypt(string, cost?) Returns a bcrypt hash of a string bcrypt(var.password, 10)
uuid() Returns a randomly generated UUID string uuid() β†’ "da3df..."
uuidv5(namespace, name) Returns a deterministic UUID v5 uuidv5("dns", "example.com")
filemd5(path) Returns the MD5 hash of a file filemd5("app.zip")
filesha256(path) Returns the SHA-256 hash of a file filesha256("lambda.zip")

Practical Hash Example: Triggering Lambda Redeployment on Code Change

A very common pattern is using filesha256 to force a Lambda function to redeploy only when its deployment package actually changes:

Example showing how to create an AWS Lambda function with Terraform and redeploy only when the zip file changes:



resource "aws_lambda_function" "api" {
function_name = "my-api"
filename = "lambda.zip"

# Only redeploy when the zip file content changes
source_code_hash = filesha256("lambda.zip")

runtime = "python3.11"
handler = "main.handler"
role = aws_iam_role.lambda.arn
}

This demonstrates creating a Lambda function with Python runtime and automatic updates triggered only when the deployment package changes.

IP Network Functions

IP network functions help you work with CIDR blocks β€” splitting them, calculating subnet addresses, and checking whether an IP falls within a range. These are invaluable for networking configurations.

Function What It Does Example
cidrhost(prefix, hostnum) Returns the IP address of a specific host in a CIDR block cidrhost("10.0.0.0/24", 5) β†’ "10.0.0.5"
cidrnetmask(prefix) Returns the subnet mask of a CIDR block cidrnetmask("10.0.0.0/24") β†’ "255.255.255.0"
cidrsubnet(prefix, newbits, netnum) Calculates a subnet address within a CIDR block cidrsubnet("10.0.0.0/16", 8, 1) β†’ "10.0.1.0/24"
cidrsubnets(prefix, newbits...) Returns multiple consecutive subnets from a CIDR block cidrsubnets("10.0.0.0/16", 4, 4, 4)
cidrcontains(cidr, ip) Returns true if an IP is within a CIDR range cidrcontains("10.0.0.0/24", "10.0.0.50") β†’ true

Practical IP Example: Generating Subnets Dynamically for a VPC

Example showing how to create multiple public subnets from a VPC CIDR block using locals and cidrsubnets():



variable "vpc_cidr" { default = "10.0.0.0/16" }

locals {
# Automatically slice the VPC CIDR into 3 equal /24 subnets
subnet_cidrs = cidrsubnets(var.vpc_cidr, 8, 8, 8)
# Result: ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"]
}

resource "aws_subnet" "public" {
count = length(local.subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = local.subnet_cidrs[count.index]
availability_zone = data.aws_availability_zones.available.names[count.index]
}

This demonstrates splitting a VPC CIDR into multiple /24 subnets and creating public subnets dynamically with Terraform.

How env zero Helps You Get More From Terraform Functions

Terraform functions are powerful on their own β€” but they become even more valuable when your entire team is using them consistently, inside approved module patterns, with policy guardrails that catch misuse before it reaches production.

env zero gives platform and cloud teams the layer of governance that Terraform does not ship with:

  • Standardised modules β€” reusable patterns that already use the right functions for naming, tagging, and networking, so every team starts from a solid baseline.
  • Policy enforcement β€” automated checks that validate resource naming conventions, required tags, and CIDR configurations before a terraform apply is allowed to run.
  • Drift detection β€” if someone bypasses Terraform and makes a manual change, env zero flags the drift immediately so your functions-generated names and tags stay the source of truth.
  • Cost visibility β€” tags generated using merge, format, and lower feed directly into env zero's cost attribution dashboards, so you can see spending by team, project, and environment without any extra work.

Whether you are just starting with Terraform functions or building a mature, multi-team IaC platform, env zero is designed to help you scale confidently.

Frequently Asked Questions

Can I define my own functions in Terraform?

No β€” Terraform does not currently support user-defined functions. You work with the built-in library. However, you can achieve similar reuse through locals (for computed values), modules (for reusable patterns), and expressions. The Terraform team has discussed custom functions as a future feature, and OpenTofu has begun exploring this capability.

Where can I use functions in Terraform?

Functions can be used anywhere Terraform evaluates an expression β€” inside resource arguments, variable defaults, locals, outputs, and data source arguments. They cannot be used in the terraform block itself (for backend configuration), as that block is evaluated before variables are available.

What is the difference between locals and functions?

Functions are built-in operations that transform a value β€” like upper() converting a string to uppercase. Locals are named values you define yourself, which can call functions. You typically combine them: use a function inside a local to compute a reusable value once, then reference the local throughout your configuration.

Are Terraform functions the same in OpenTofu?

Yes β€” OpenTofu is a fork of Terraform and supports the same built-in function library. OpenTofu 1.7 and later also added provider-defined functions, which allow Terraform providers to ship their own custom functions. This is a capability that does not yet exist in Terraform itself.

How do I debug a Terraform function call?

The easiest way is to use a terraform console session. Run terraform console in your working directory and type function calls interactively to see their output immediately. It is the fastest way to test expressions without running a full plan.

Schedule a technical demo
See env zero in action
Schedule demo

Related Content

All articles