Terraform

Terraform Strings: Interpolation, Multiline & Built-in Functions

Terraform Strings: Interpolation, Multiline & Built-in Functions

In this article, we will take a look at strings in Terraform, firstly explaining what they are before looking at interpolation with some practical examples. Terraform provides lots of built-in functions you can use with strings, so we will then look at how you can use each to manipulate your strings, again with a practical example of each. Lastly, we will look at string concatenation. This is the Terraform string 101!

What we will cover:

  1. What is a string in Terraform?
  2. String interpolation in Terraform
  3. Multiline string in Terraform
  4. Terraform string functions
  5. How to concatenate strings in Terraform?

What is a string in Terraform?

In Terraform, a string is a sequence of characters used to represent text data. It is one of the fundamental data types used to define configuration values. Strings in Terraform are typically used for configuration values, resource attributes, and variables.

There are two main ways to define strings:

  1. Quoted strings – A quoted string is enclosed in straight double-quote characters (e.g., "hello"). Quoted strings support escape sequences like \\n for newline, \\t for tab, and \\\" for a literal quote.
  2. Heredoc strings – Terraform also supports a special syntax called heredoc string for defining multi-line strings or strings that contain special characters. Inspired by Unix shell languages, these are useful when you need to write more complex configurations.
<<EOT
hello
world
EOT

String literals in Terraform

String literals are sequences of characters enclosed in double quotes (“) used to represent textual data in Terraform configuration files. They can contain any valid UTF-8 characters, including letters, digits, punctuation, and special characters.

variable "example" {
  default = "Hello, World!"
}

String interpolation in Terraform

Interpolation refers to the process of embedding expressions within strings to dynamically insert values from various sources. Interpolation allows you to create configurations that adapt based on variables or resource attributes. By using variables and interpolation, you can write reusable code snippets that can be applied to different scenarios with varying values.

What is Terraform string interpolation?

Terraform allows embedding expressions within strings using ${expression} syntax, which. lets you dynamically insert values from variables, data sources, or function calls into your configurations. Well-written interpolation can make your Terraform code can reduce code duplication and make it easier to understand.

The expression within the curly braces can be:

  • Variable reference: You can reference a variable defined in your Terraform code using var.name. For example, ${var.region} would insert the value of the variable named region.
  • Attribute reference: You can access the attributes of the resources you’ve defined. The syntax is similar to variable reference, but with the resource name preceding the attribute, like aws_instance.webserver.public_ip.
  • Function call: Terraform provides built-in functions for various tasks like string manipulation, file reading, etc. You can use these functions within interpolation like ${file("config.txt")} to read the contents of a file.
  • Simple math expressions: You can perform basic arithmetic operations within interpolation. For example, ${count.index * 2} would multiply the current index of a loop by two.

If you need to include a literal ${var.name} string within your configuration, you can escape the interpolation with double dollar signs: $${var.name}.

Interpolation examples

The Terraform interpolation example using variables below assigns the value “Hello, world!” to the message attribute of the example_resource:

variable "greeting" {
  type    = string
  default = "Hello"
}

resource "example_resource" "example" {
  message = "${var.greeting}, world!"
}

The next attribute reference example outputs “The resource name is example-name”:

resource "example_resource" "example" {
  name        = "example-name"
  description = "This is an example resource with ID ${example_resource.example.id}"
}

output "example_output" {
  value = "The resource name is ${example_resource.example.name}"
}

Multiline string in Terraform

For multiline strings, Terraform provides a heredoc syntax, which is one of the most common and straightforward methods. Heredoc strings start with <<EOF (or any identifier) and end with EOF, where EOF stands for ‘end of file’.

How to write multiline strings in Terraform?

The Terraform code example below defines a multiline description:

resource "example_resource" "example" {
  name        = "example-name"
  description = <<EOF
This is an example resource.
This description spans multiple lines.
EOF
}

In the next example, EOF marks the end of the multiline string assigned to the command argument:

variable "configuration" {
  type = string
}

resource "null_resource" "example" {
  provisioner "local-exec" {
    command = <<EOF
      echo "${var.configuration}" > config.txt
    EOF
  }
}

Terraform string functions

Terraform provides several built-in string functions you can use to manipulate and transform string values within your configurations. These functions allow you to perform various tasks like formatting, searching, extracting substrings, and case conversion. 

Here’s a list of the Terraform string functions:

  • base64decode()
  • join()
  • regex() 
  • replace()
  • split() 
  • lower() 
  • substr() 
  • trim() 
  • upper()

Learn more about built-in Terraform functions: Terraform Functions, Expressions, Loops (Examples).

1. base64decode() function

The base64decode function is used in Terraform to decode a Base64-encoded string. This function takes a Base64-encoded string and returns the decoded value as a plain string.

Syntax:

base64decode(encodedString)

Example:

variable "encoded_value" {
  description = "A Base64-encoded string"
  default     = "SGVsbG8sIFRlcnJhZm9ybSE="  # "Hello, Terraform!" in Base64
}

resource "local_file" "example" {
  filename = "${path.module}/decoded_output.txt"
  content  = base64decode(var.encoded_value)
}

output "decoded_value" {
  value = base64decode(var.encoded_value)
}
  • encoded_value is a variable that holds a Base64-encoded string. The example value "SGVsbG8sIFRlcnJhZm9ybSE=" decodes to "Hello, Terraform!".
  • A local_file resource is used to create a file named decoded_output.txt in the current module’s directory.
  • The content attribute of the file is set to the decoded value of encoded_value using the base64decode function.
  • The decoded_value output shows the decoded string, which can be used for further processing or debugging.

2. join() function

The Terraform join function creates a string by concatenating all elements of a list with a specified separator. To learn more about this function, see: How to Use Terraform Join and Split Functions with Strings.

Syntax:

join(delimiter, list)

Example:

variable "environment" {
  type = string
}

resource "aws_instance" "web_server" {
  count = 2

  # ... other instance configuration options

  tags = {
    Name = join("-", ["web-server", var.environment, count.index + 1])
  }
}

In this example, we created an AWS instance with a name that combines a base name, an environment identifier (stored in a variable), and a running instance count (obtained from a count meta-argument).

The join() function combines three elements, "web-server" (static text), var.environment (variable reference), count.index + 1 (expression to get the current instance number). The delimiter specified is “-”. The resulting string will be used as the value for the Name tag of each instance (e.g., “web-server-production-1”, “web-server-production-2”).

3. regex() function

The regex() function is used in Terraform code to perform regular expression matching on a string. regex() attempts to match the pattern against the entire string and returns the first match found in the string. If the pattern doesn’t match, regex() throws an error. For regular expressions, Terraform uses the re2 library, which supports a rich set of features for pattern matching.

You can use regex() to ensure that variables or input values conform to a specific format. For example, you might want to validate email addresses, domain names, or resource names.

Regular expressions can be powerful tools for extracting specific parts of a string that match a particular pattern. This can be useful for parsing log files, configuration data, or API responses.

regex() can also be used in conjunction with conditional statements (e.g., if) to control behavior based on the presence or absence of specific patterns in strings.

Syntax:

regex(pattern, string)

Example:

variable "example_string" {
  description = "A string containing a version number"
  default     = "The current version is v1.2.3"
}

locals {
  version_pattern = "v([0-9]+\\.[0-9]+\\.[0-9]+)"
  extracted_version = regex(local.version_pattern, var.example_string)[0]
}

output "extracted_version" {
  value = local.extracted_version
}
  • example_string is a variable that holds a string containing a version number.
  • version_pattern is a local variable that holds the regular expression pattern to match a version number (e.g., v1.2.3).
  • extracted_version uses the regex function to extract the version number from example_string. The [0] index is used to get the first (and, in this case, only) match from the list returned by regex.
  • The extracted_version output shows the extracted version number.

When you run terraform apply, Terraform extracts the version number v1.2.3 from the input string and displays it as an output.

4. replace() function

The replace function in Terraform is used to replace occurrences of a substring within a string with another substring. It performs a straightforward search and replace operation and returns a new string with all occurrences of the search substring replaced by the replace substring.

Use cases for the replace function include renaming resources where names might be defined in configuration files but need adjustments based on environment or deployment. You can also use replace() to remove unwanted characters or patterns from user-provided data before using it in your Terraform configuration. Many configuration formats involve replacing placeholders with actual values.

Syntax:

replace(string, search, replace)

Example:

variable "base_url" {
  type = string
  default = "https://api.example.com/"
}

variable "environment" {
  type = string
}

resource "null_resource" "api_endpoint" {
  provisioner "local-exec" {
    command = <<EOF
      echo "${var.base_url}" | replace("/api", "/api-${var.environment}")
    EOF
  }
}

In this example, we have a base URL defined in a variable, and we want to dynamically generate environment-specific URLs by replacing a placeholder string with the environment name (stored in another variable).

  • The replace() function searches for the substring "/api" within the base_url string. It replaces all occurrences with "/api-${var.environment}".
  • The resulting string, printed by the local-exec provisioner, would be the environment-specific URL (e.g., "[invalid URL removed]" for environment “production”).

5. split() function

The split function in Terraform is used to split a string into a list of substrings based on a specified delimiter. It is useful when you need to break a single string into multiple parts. Note that the list returned includes empty elements between delimiters.

This function can be helpful for processing configuration values that are provided as a single comma-separated string, parsing out individual components from a compound string, or manipulating input data to be used in other Terraform resources.

Syntax:

split(delimiter, string)
split(",", "foo,bar,baz") = ["foo", "bar", "baz"]

Examples:

In the example below, a variable named server_list stores a comma-separated list of server names (e.g., “webserver1, webserver2, database”). We want to iterate through each server name in the list and create separate resources for them.

variable "server_list" {
  type = string
}

resource "null_resource" "server" {
  for_each = split(",", var.server_list)
  provisioner "local-exec" {
    command = <<EOF
      echo "Creating server: ${each.key}"
    EOF
  }
}
  • split() is used to create a list from the comma-separated server_list.
  • The null_resource with a for_each meta-argument iterates over each element in the split list.
  • each.key refers to the current element (server name) during the iteration.
  • The local-exec provisioner simply prints a message indicating the server being created.

6. lower() function

The lower() function in Terraform converts all letters in a given string to lowercase. The function iterates through each character in the string and converts it to its lowercase equivalent based on Unicode’s definition of letters and upper- and lowercase characters. It returns a new string with all characters converted to lowercase, leaving the original string unmodified.

Terraform string comparisons are case-sensitive by default. lower() can be helpful when you want to perform comparisons regardless of the case. You can convert both strings to lowercase before comparison to ensure consistency. 

Another use case for lower() is when user input or data from external sources might have a mixed case. lower() allows you to convert everything to lowercase for easier processing or to enforce a specific format within your Terraform configuration. It can also help when generating consistent resource names. By converting parts of the name to lowercase using lower(), you can ensure a consistent naming convention regardless of the input case.

Syntax:

lower(string)

Example:

In the following example, we have a variable named user_input that stores a username. We want to create a resource with a name derived from the username but always in lowercase.

variable "user_input" {
  type = string
}

resource "null_resource" "user_account" {
  name = lower(var.user_input)

  provisioner "local-exec" {
    command = <<EOF
      echo "Creating user account for: ${lower(var.user_input)}"
    EOF
  }
}
  • lower() is used to convert the user_input to lowercase before assigning it to the resource name.
  • The local-exec provisioner also uses lower() within the printed message to ensure a consistent case for the username.

7. substr() function

The substr() function extracts substrings from a given string. It can also be used to parse data from outputs where module outputs or data sources might return strings containing structured information. 

substr() can be used to extract relevant parts for further processing. It can also construct resource names by combining static text with substrings extracted from other variables or attributes.

Syntax:

substr(string, offset, length)

substr() takes three arguments:

  • string: This is the original string from which you want to extract a substring.
  • offset: This is the starting position (index) of the substring within the original string. Indexing starts at 1 (the first character). Negative offsets are counted from the end of the string.
  • length (optional): This is the maximum length of the substring to extract. If omitted, the function will extract characters from the offset position until the end of the string.

Example:

variable "example_string" {
  description = "A string from which to extract a substring"
  default     = "Terraform"
}

locals {
  extracted_substring = substr(var.example_string, 0, 4)
}

output "substring_output" {
  value = local.extracted_substring
}

When we run terraform apply, Terraform extracts the substring “Terr” from the input string “Terraform” and displays it as an output.

Let’s look at the next example:

variable "example_string" {
  description = "A string containing a date"
  default     = "2024-07-09"
}

locals {
  year  = substr(var.example_string, 0, 4)
  month = substr(var.example_string, 5, 2)
  day   = substr(var.example_string, 8, 2)
}

output "year" {
  value = local.year
}

output "month" {
  value = local.month
}

output "day" {
  value = local.day
}
  • example_string holds a date string in the format YYYY-MM-DD.
  • year extracts the first four characters (the year) from the date string.
  • month extracts the two characters representing the month.
  • day extracts the two characters representing the day.
  • year, month, and day show the extracted parts of the date string.

When we run terraform apply here, Terraform will extract and display the year, month, and day parts of the date string separately.

8. trim() function

The Terraform trim() function removes specified characters from the start and end of a given string. It is often used to clean user input, which can often contain leading or trailing spaces, especially when obtained from forms or text fields. It can also help when data retrieved from external sources like APIs or configuration files might have leading or trailing whitespace due to formatting or transfer protocols. 

In some cases, the trim() function can be used to ensure that variables or configuration values have no leading or trailing whitespace for consistency.

Syntax:

trim(string, trimset)

trim() takes one or two arguments:

  • string: This is the string you want to remove leading and/or trailing whitespace characters from.
  • trimset (optional): This is an optional argument specifying a set of characters to remove in addition to the default whitespace characters.

Example:

variable "example_string" {
  description = "A string with leading and trailing whitespace"
  default     = "   Hello, Terraform!   "
}

locals {
  trimmed_string = trim(var.example_string, " ")
}

output "trimmed_output" {
  value = local.trimmed_string
}

In this example, trim() removes any leading or trailing whitespace characters from the user_name variable before including it in the printed message.

Note there are other related functions:

  • trimprefix: Removes a word from the start of a string.
  • trimsuffix: Removes a word from the end of a string.
  • trimspace: Removes all types of whitespace from both the start and end of a string.

9. upper() function

Similar to the lower() function, the Terraform upper() converts all characters to uppercase. This can be useful for normalizing input strings, ensuring consistency in string comparisons, or preparing strings for use in case-sensitive contexts.

Syntax:

upper(string)

Example:

upper(hello) = HELLO

How to concatenate strings in Terraform?

Terraform offers two main methods for concatenating strings — string interpolation with ${} and the join() function.

  • String Interpolation with ${} – This is the simpler approach for interpolating variable values or expressions directly into strings. The expression can be a variable reference (e.g., ${var.name}), an attribute reference (e.g., >${aws_instance.webserver.public_ip}), or even a simple math expression (e.g., ${count.index * 2}). Terraform evaluates the expression and inserts the result into the string at the point of interpolation.
  • join() function – This method provides more flexibility for combining multiple strings with a specified delimiter. See notes on this in the section above.

Let’s look at a string interpolation example:

variable "first_part" {
  description = "The first part of the string"
  default     = "Hello"
}

variable "second_part" {
  description = "The second part of the string"
  default     = "World"
}

locals {
  concatenated_string = "${var.first_part}, ${var.second_part}!"
}

output "concatenated_output" {
  value = local.concatenated_string
}

The output here would be Hello, World!.

Managing Terraform with Spacelift

Terraform is really powerful, but to achieve an end-to-end secure Gitops approach, you need to use a product that can run your Terraform workflows. Spacelift takes managing Terraform to the next level by giving you access to a powerful CI/CD workflow and unlocking features such as:

  • Policies (based on Open Policy Agent) – You can control how many approvals you need for runs, what kind of resources you can create, and what kind of parameters these resources can have, and you can also control the behavior when a pull request is open or merged.
  • Multi-IaC workflows – Combine Terraform with Kubernetes, Ansible, and other infrastructure-as-code (IaC) tools such as OpenTofu, Pulumi, and CloudFormation,  create dependencies among them, and share outputs
  • Build self-service infrastructure – You can use Blueprints to build self-service infrastructure; simply complete a form to provision infrastructure based on Terraform and other supported tools.
  • Integrations with any third-party tools – You can integrate with your favorite third-party tools and even build policies for them. For example, see how to Integrate security tools in your workflows using Custom Inputs.

Spacelift enables you to create private workers inside your infrastructure, which helps you execute Spacelift-related workflows on your end. For more information on configuring private workers, refer to the documentation.

If you want to learn more about Spacelift, create a free account today, or book a demo with one of our engineers.

Key points

Terraform provides a rich feature set of built-in functions for string manipulation and allows string concatenation. Multiline strings are handled using the heredoc string syntax.

Note: New versions of Terraform are placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that expands on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6.

Automate Terraform Deployments with Spacelift

Automate your infrastructure provisioning, and build more complex workflows based on Terraform using policy as code, programmatic configuration, context sharing, drift detection, resource visualization, and many more.

Learn more

The Practitioner’s Guide to Scaling Infrastructure as Code

Transform your IaC management to scale

securely, efficiently, and productively

into the future.

ebook global banner
Share your data and download the guide