Skip to content

Terraform Built-in Functions: Format, Merge, File & More

DodaTech 4 min read

Terraform built-in functions are expressions that transform, combine, and manipulate values, enabling dynamic and flexible configurations without external tools or scripts.

What You'll Learn

In this tutorial, you will learn how to use Terraform built-in functions for string formatting, collection manipulation, file operations, type conversion, and numeric computation to write expressive configurations.

Why It Matters

Functions eliminate hardcoded values and manual string concatenation. They let you generate resource names, merge tag maps, read files for user data scripts, and transform data structures -- all within Terraform's declarative model.

Real-World Use

DodaTech uses the format function for consistent resource naming, merge for combining default and environment-specific tags, and file for loading CloudFormation templates and user data scripts into Durga Antivirus Pro's EC2 instances.

String Functions

Format

The format function produces formatted strings using printf-style syntax:

locals {
  name_prefix = "dodatech"
  environment = "production"

  instance_name = format("%s-%s-web-01", local.name_prefix, local.environment)
  db_identifier = format("db-%s-%s", local.name_prefix, local.environment)
}

output "names" {
  value = {
    instance = local.instance_name
    database = local.db_identifier
  }
}

Expected output:

names = {
  database = "db-dodatech-production"
  instance = "dodatech-production-web-01"
}

Join and Split

locals {
  security_groups = ["sg-12345", "sg-67890", "sg-abcde"]

  sg_list   = join(", ", local.security_groups)
  sg_arn    = format("arn:aws:ec2:us-east-1:123456789012:security-group/%s", local.sg_list)
}

output "security_group_arn" {
  value = local.sg_arn
}

Expected output:

security_group_arn = "arn:aws:ec2:us-east-1:123456789012:security-group/sg-12345, sg-67890, sg-abcde"

Lower, Upper, and Title

locals {
  raw_name = "DODA-TECH-WEB-SERVER"
  clean    = lower(local.raw_name)
  title    = title(local.clean)
}

output "formatted" {
  value = {
    original = local.raw_name
    lower    = local.clean
    title    = local.title
  }
}

Expected output:

formatted = {
  lower    = "doda-tech-web-server"
  original = "DODA-TECH-WEB-SERVER"
  title    = "Doda-Tech-Web-Server"
}

Collection Functions

Merge

Combines multiple maps into one, with later maps overriding earlier keys:

locals {
  default_tags = {
    ManagedBy = "Terraform"
    Project   = "DodaTech"
  }

  environment_tags = {
    Environment = "production"
    CostCenter  = "Infrastructure"
  }

  all_tags = merge(local.default_tags, local.environment_tags, {
    Name = "web-server"
  })
}

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  tags          = local.all_tags
}

Expected output: The instance has four tags: ManagedBy, Project, Environment, CostCenter, and Name. The merge order ensures environment tags override defaults.

Flatten

Converts nested lists into a flat list:

locals {
  cidr_blocks = flatten([
    ["10.0.1.0/24", "10.0.2.0/24"],
    ["10.0.3.0/24", "10.0.4.0/24"],
  ])
}

output "flat_cidrs" {
  value = local.cidr_blocks
}

Expected output:

flat_cidrs = [
  "10.0.1.0/24",
  "10.0.2.0/24",
  "10.0.3.0/24",
  "10.0.4.0/24",
]

File Function

The file function reads the contents of a file at the given path:

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  user_data = file("${path.module}/scripts/bootstrap.sh")
}

Expected output: Terraform reads scripts/bootstrap.sh relative to the current module directory and passes its contents as user data to the EC2 instance.

Templatestring with File

locals {
  environment = "production"
  app_version = "2.5.1"

  user_data = templatefile("${path.module}/templates/user_data.tftpl", {
    env     = local.environment
    version = local.app_version
  })
}

Expected output: Reads a template file, replaces ${env} and ${version} placeholders with the local values, and returns the rendered string.

Numeric Functions

locals {
  desired_capacity = 4
  max_capacity     = 10
  min_capacity     = 2

  # Ensure values stay within bounds
  safe_desired = max(local.min_capacity, min(local.desired_capacity, local.max_capacity))
}

output "auto_scaling_config" {
  value = {
    min    = local.min_capacity
    max    = local.max_capacity
    desired = local.safe_desired
  }
}

Expected output:

auto_scaling_config = {
  desired = 4
  max     = 10
  min     = 2
}

Common Mistakes

1. Forgetting Function Parentheses

Terraform functions always require parentheses: lower("HELLO") not lower "HELLO".

2. Passing Wrong Types

Using merge with lists or flatten with maps causes type errors. Verify function signatures in the Terraform documentation.

3. File Path Resolution

The file function uses paths relative to the current module. Using absolute paths or paths outside the module directory causes errors.

4. Template Syntax Conflicts

Using ${} inside template files for non-Terraform purposes (like shell variables) causes interpolation errors. Escape with $${}.

5. Nested Function Readability

Deeply nested function calls like merge(lookup(var.config, "tags", {}), var.default_tags, ...) are hard to read. Use intermediate locals.

Practice Questions

1. What does the merge function do? Combines multiple maps into one. Later maps override keys from earlier maps.

2. How do you read a file into a Terraform configuration? Use the file function: file("${path.module}/filename.txt").

3. What is the difference between format and join? format creates a string with printf-style formatting. join concatenates list elements with a separator.

4. How does the templatefile function differ from file? file reads raw content. templatefile reads content and renders template variables with values from a map.

5. Challenge: Write a configuration that uses format, merge, file, flatten, and max/min functions to create resource names, tags, user data, subnet lists, and scaling constraints.

Mini Project: Function-Driven Configuration

Create a configuration that reads a user-data template from a file, merges default and environment tags, formats resource names, flattens subnet CIDR lists from a nested variable, and clamps scaling values within bounds.

Dynamic Blocks
Terraform Import

What's Next

Use Terraform built-in functions to write dynamic configurations, then learn Terraform Import to bring existing infrastructure under IaC management.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro