Forem

Cover image for Terraform Split and Join Functions: Examples and Best Practices
env0 Team for env0

Posted on • Originally published at env0.com

Terraform Split and Join Functions: Examples and Best Practices

The HashiCorp Configuration Language (HCL) comes with many built-in functions, the major ones including:

  • Numeric functions for working with the number type
  • Collection functions for managing complex data structures
  • Encoding functions for encoding and decoding data
  • String functions for string manipulation

The string functions category contains many functions to manipulate strings in different ways. Two such functions are split and join. In this blog post, we will explore these two functions, how they work, and what they are used for.

Disclaimer: All use cases of Terraform join and split functions discussed here work similarly in OpenTofu, the open-source Terraform alternative. However, to keep it simple and familiar for DevOps engineers, we will refer to these as “Terraform split” and “Terraform join” throughout this blog post.

Terraform split Function

The split function is a built-in function that takes a string input and a separator that determines where the input string will be divided. The output is a list of strings.

Syntax of the Terraform split function

The syntax of the Terraform split function is:

split(separator, string)
Enter fullscreen mode Exit fullscreen mode

The split function has two arguments:

  • separator is what the input string should be split on
  • string is the value that should be split into a list of strings 

To show how the split function works, here is a basic example using the terraform console command for splitting a static string:

$ terraform console
> split(",", "value1,value2,value3,value4")
tolist([
  "value1",
  "value2",
  "value3",
  "value4",
])
Enter fullscreen mode Exit fullscreen mode

The separator argument does not have to be a single character; it could be an arbitrary string:

$ terraform console
> split("---", "value1---value2---value3")
tolist([
  "value1",
  "value2",
  "value3",
])
Enter fullscreen mode Exit fullscreen mode

Use cases for the Terraform split function

The split function is used for a variety of use cases involving splitting strings.

A few of the most common use cases are:

  • Parsing the value of an input variable from a string to an array, e.g., a comma-separated list of subnet names
  • Extracting parts of a string identifier, e.g., an Amazon Resource Name (ARN) string
  • Removing a part of a string value, e.g., a leading "https://"

Alternatives to the Terraform split function

There are a number of alternative built-in functions to the split function, depending on what your goal is.

If you want to remove parts of a string you can instead use the replace function:

$ terraform console
> replace(
  "https://docs.env0.com/docs/getting-started",
  "https://",
  "")
"docs.env0.com/docs/getting-started"
Enter fullscreen mode Exit fullscreen mode

The replace function is more intuitive for this specific use case compared to splitting strings at the substring you want to remove.

If you want to extract all subnet names from a comma-separated string you could use the regexall function together with the flatten function:

$ terraform console
> flatten(regexall("([a-z0-9-]+)", "subnet-1,subnet-2,subnet-3"))
[
  "subnet-1",
  "subnet-2",
  "subnet-3",
]
Enter fullscreen mode Exit fullscreen mode

Terraform split Examples

Let's see some examples to understand how to use this function.

Parsing values of input variables

Let's assume you have a variable in your Terraform configuration that expects a string of subnet names separated by commas. You want to use the subnet names to create AWS subnet resources for each name.

The variable is defined in your variables.tf file:

variable "subnet_names" {
  type    = string
  default = "subnet-1,subnet-2,subnet-3"
}
Enter fullscreen mode Exit fullscreen mode

Use a local value in your network.tf file to get the individual names of the subnets from the input variable with the split function:

locals {
  subnet_names = split(",", var.subnet_names)
}
Enter fullscreen mode Exit fullscreen mode

In the same file, define your AWS VPC resource and use the local.subnet_names value to create a number of subnet resources in the VPC:

resource "aws_vpc" "this" {
  cidr_block = "10.100.10.0/24"
}

resource "aws_subnet" "all" {
  count  = length(local.subnet_names)
  vpc_id = aws_vpc.this.id
  # the rest of the attributes are omitted
}
Enter fullscreen mode Exit fullscreen mode

Extracting parts of a string identifier

Resources that you create in Terraform using a given cloud provider have some identifier string in their respective cloud. For AWS, resources have an Amazon Resource Name (ARN).

An example of an ARN for an AWS EC2 virtual machine is:

arn:aws:ec2:eu-west-1:123456789012:instance/i-0fb379ac92f436969
Enter fullscreen mode Exit fullscreen mode

An ARN is the concatenation of a few different strings to form a unique identifier for the resource. The ARN includes the service name (ec2), the AWS region (eu-west-1), the account ID (123456789012), and more. Each part is separated by a colon.

Sometimes you need to access one or more string values from an ARN to use elsewhere in your Terraform configuration. This is a great use case for split function.

You can use local values to extract the parts that you are interested in. An example of an AWS EC2 instance is this:

resource "aws_instance" "web" {
  # arguments omitted for brevity
}

locals {
  arn = split(":", aws_instance.web.arn)
  region = local.arn[3] # eu-west-1
  account_id = local.arn[4] # 123456789012
  instance_id = local.arn[5] # instance/i-0fb379ac92f436969
}
Enter fullscreen mode Exit fullscreen mode

Removing a part of a string value

You may have an input variable value, or an attribute of a resource or data source, that represents a web address. This string value often starts with "http://" or "https://". However, the place in your Terraform configuration where you want to use this value might expect a value without "http://" or "https://".

You can use the split function to remove unwanted parts of a string. Note that if you remove the leading part of a string, the return value of the split function will include an empty string as the first value, for example:

$ terraform console
> split("https://", "https://google.com")
tolist([
  "",
  "google.com",
])
Enter fullscreen mode Exit fullscreen mode

You’ll need to take this into account in your Terraform configuration.

Here’s an example of taking a full URL and extracting parts of it:

locals {
  full_url  = "https://docs.env0.com/docs/getting-started"

  # docs.env0.com/docs/getting-started
  first     = split("https://", local.full_url)[1] 

  # docs.env0.com
  subdomain = split("/", local.first)[0]
}
Enter fullscreen mode Exit fullscreen mode

Terraform join Function

The Terraform join function is a built-in function that performs the opposite job of the split function. The join function is used to combine a list of string values into a single string.

Syntax of the Terraform join function

The syntax of the join function in Terraform CLI is:

join(separator, list)
Enter fullscreen mode Exit fullscreen mode

There are two arguments for the join function:

  • separator is a string that will be inserted between each element in the list of string values
  • list is the list of string values that should be joined together

The output will be a single string made up of the list of input strings, with the specified delimiter in between. You can combine values from different source objects: static strings, resource attributes, input variables, and more.

Let's use the terraform console command to show how the join function works. This is a basic example of joining a static list of strings, i.e., string concatenation:

$ terraform console
> join(",", ["value1", "value2", "value3", "value4"])
"value1,value2,value3,value4"
Enter fullscreen mode Exit fullscreen mode

The separator argument does not have to be a single character; it could be any string value:

$ terraform console
> join("---", ["value1", "value2", "value3"])
"value1---value2---value3"
Enter fullscreen mode Exit fullscreen mode

In fact, the separator could also be an empty string:

$ terraform console
> join("", ["value1", "value2", "value3"])
"value1value2value3"
Enter fullscreen mode Exit fullscreen mode

Use cases of the Terraform join function

A few of the most common use cases for the join function:

  • Build URL and file path strings
  • Building resource identifiers

The general use case is to combine data from various sources into a single string.

Alternatives to the Terraform join function

The most common alternative to the join function is string interpolation –. this is when you include other values in a string using the ${...} syntax. 

A simple example of string interpolation in a local value is shown below:

variable "domain" {
  type = string
  default = "docs.env0.com"
}

variable "path" {
  type = string
  default = "docs/getting-started"
}

locals {
  url = "https://${var.domain}/${var.path}" #
}
Enter fullscreen mode Exit fullscreen mode

Another alternative to the join function is the built in function named format:

$ terraform console
> format("%s,%s,%s", "subnet-1", "subnet-2", "subnet-3")
"subnet-1,subnet-2,subnet-3"
Enter fullscreen mode Exit fullscreen mode

The format function can do much of what the Terraform join function can do, but is not intended for the same use cases.

Terraform join Examples

Let's see some examples that illustrate how to use the Terraform join function.

Build URL and file path strings

If you need to combine multiple separate strings into a file path or URL the join function is useful. These strings could be input variables, local values, resource attributes, or static strings.

Let's assume you have a number of variables representing parts of a website URL that you need to combine to form a full URL:

variable "domain" {
  type = string
  default = "docs.env0.com"
}

variable "path" {
  type = string
  default = "docs/getting-started"
}

locals {
  # note that it should be "https:/" with a single "/" due to the separator being a "/"
  url = join("/", ["https:/", var.domain, var.path)
}
Enter fullscreen mode Exit fullscreen mode

A similar use case is to build file paths. Here is an example of using the local provider to read an existing configuration file for an environment based on the value of an input variable:

variable "environment" {
  type = string
  validation {
    condition     = contains(["dev", "prod"], var.environment)
    error_message = "Use an valid environment name"
  }
}

data "local_file" "config" {
  filename = join("/", [path.module, "config", "${var.environment}.conf"])
}
Enter fullscreen mode Exit fullscreen mode

Building resource identifiers

In a similar manner to how you used the split function to split an ARN identifier into parts, it is common to also have to build an identifier from its parts. This is a common use case for the join function.

In AWS resources have ARNs, and in Azure each resource has a resource ID. The resource ID is a string presented in the following format:

/subscriptions/<guid>/resourceGroups/<name>/providers/<provider>/<type>/<name>
Enter fullscreen mode Exit fullscreen mode

There are a few static strings and a few varying strings, depending on the type of resource that the ID is for.

It is common for you to have to build these resource IDs from parts, as shown in the following simple example:

variable "storage_account_name" {
  type = string
}

data "azurerm_client_config" "current" {}

resource "azurerm_resource_group" "this" {
  # arguments omitted for brevity
}

locals {
  resource_id = join("/", [
    "/subscriptions",
    data.azurerm_client_config.current.subscription_id,
    "resourceGroups",
    azurerm_resource_group.this.name,
    "providers",
    "Microsoft.Storage",
    "storageAccounts",
    var.storage_account_name
  ])
}
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

It is easy to manipulate data in HCL using the many built-in functions.

String manipulation functions are among the most used functions. The split and join functions are heavily used for tasks that require splitting strings into separate parts or combining different strings into a single string.

A common use case for the join function is building URLs, file paths, and resource identifiers from static strings, input variables, local values and resources, and data source attributes.

A common use case for the split function is to divide URLs, file paths, or resource identifiers to get specific parts from these strings.

The split and join functions perform opposite tasks.

Frequently Asked Questions

Q. How do you join a variable and a string?

Create a list of all the different objects you want to join and pass it to the join function:

$ terraform console
> join(",", [var.subnet_eu_west_1a, var.subnet_eu_west_1b, "subnet-1"])
"subnet-eu-west-1a,subnet-eu-west-1b,subnet-1"
Enter fullscreen mode Exit fullscreen mode

Q. How do you join two lists?

Join elements from two or more lists of strings by passing all the lists to the join function:

$ terraform join
> join(",", ["subnet-1", "subnet-2"], ["subnet-3", "subnet-4"])
"subnet-1,subnet-2,subnet-3,subnet-4"
Enter fullscreen mode Exit fullscreen mode

Q. How do you split a string on a substring?

Use the split function to split a string on a specified separator substring:

$ terraform console
> split(",", "subnet-1,subnet-2,subnet-3")
tolist([
  "subnet-1",
  "subnet-2",
  "subnet-3",
])
Enter fullscreen mode Exit fullscreen mode

Top comments (0)