Terraform provides a greater ability to define Infrastructure as Code (IaC) through its support of Expressions. Expressions are lines of code that define configuration and attributes on resources in the Terraform HCL code as the Terraform code is executed with the terraform plan command. This enables a rich ability to dynamically configure resources based on passed input variables to the Terraform Project, or even via looking up other resources managed by the same Terraform Project. There is a huge variety to the different code expressions that can be written in Terraform to suit the requirements of different Infrastructure as Code projects.

Terraform expressions support many built-in functions to help writing the expression code needed for a solutions infrastructure definition. When using a Terraform list type to define an Array of value or objects, it may be necessary at times to lookup those values programmatically.



Basic use of index() Function

The Terraform index() function can be used to lookup the index location of a value in a list. The function accepts an argument that is a reference to the list to search, and an argument that is the value to lookup the index for within the list.

The following is an example usage of the index() function to find the index of a value in a simple list of string values:

locals {
  myList = ["a", "b", "c", "d", "e"]

  # Get index for "c" value in list
  myValueIndex = index(local.myList, "c")
  # myValueIndex will equal 2
}

The previous example shows how simple it is to use the index() function to retrieve the index of a value within a list of strings (aka list(string)). This can be used exactly the same way to lookup the index of values in a list of numbers (aka list(number)) too.

The following is an example usage of the index() function to find the index of a value in a simple list of numbers:

locals {
  myList = [1966, 2063, 1989]

  # Get index for 2063 value in list
  myValueIndex = index(local.myList, 2063)
  # myValueIndex will equal 1
}

Get Index of Object in List via Attribute Value

It’s probably most common to lookup values within a Terraform list that contains numbers or strings. There are also times when the list may contain objects that have their own attributes. Using the index() method to lookup a values index in an object list (aka list(object)) doesn’t work by passing the object itself as the value to the index() function.

To use the index() function on a list of objects (list(object)) to find the index of an object in the list by looking up the value of an attribute on the object is performed with the help of a splat expression that that converts the list(object) to a list of the values needed for the lookup.

The following is an example of using a splat lookup on a list of objects to lookup the index of the object in the list with the name attribute set to the value being looked up:

locals {
  objList = [
    { name = "Chris" },
    { name = "Dan" }
  ]

  # Get index for Object with name equal to "Dan" in list
  myObjIndex = index(local.objList.*.name, "Dan")
  # nameIndex will equal 1
}

The previous example shows the use of a splat expression using the * symbol that iterates over all the objects / elements in the list to the left of the * symbol and accesses the attribute given to the right of it. This splat expression is a shorthand for using a for expression to create a list of the values of the given attribute on the objects / elements in the source list.

The following is an expanded example of the previous example of a splat expression that uses the for expression instead to help better understand how this works:

locals {
  objList = [
    { name = "Chris" },
    { name = "Dan" }
  ]

  # Create List of 'name' values from source objet list
  listOfNames = [for v in local.objList : v.name]

  # Get index for 'name' equal to "Dan"
  nameIndex = index(local.listOfNames, "Dan")
  # nameIndex will equal 1
}

To compress the for expression usage into a single line expression that performs the same index value lookup as the splat expression is as follows:

locals {
  objList = [
    { name = "Chris" },
    { name = "Dan" }
  ]

  # splat expression index lookup
  myObjIndexSplat = index(local.objList.*.name, "Dan")

  # for expression index lookup
  myObjIndexFor = index([for v in local.objList : v.name], "Dan")
}

Retrieve List Element by Index

Once the index of an element in a list is known, then the value of that element can be retrieved from the list. This can be performed in a similar syntax to retrieving array elements in other programming languages by their index. Also, just as Arrays in most other programming languages start with an index of zero (0) for the first element in the Array, so is the list type in Terraform.

The following is the syntax for retrieving an element from a list by index:

list[index]

The following is an example of retrieving an element from a list by index:

locals {
  myList = ["a", "b", "c", "d"]

  value = local.myList[1]
  # value is equal to "b"
}

To close things off, the following are several examples of retrieving elements from lists using the previous index() function code examples of looking up the element index values:

locals {
  myList = ["a", "b", "c", "d"]

  # lookup value by index of specific value
  stringValue = local.myList(index(local.myList, "b"))

  objList = [
    { name = "Chris" },
    { name = "Dan" }
  ]

  # splat expression index lookup of object list
  objValue1 = local.objList[index(local.objList.*.name, "Dan")]

  # for expression index lookup of object list
  objValue2 = local.objList(index([for v in local.objList : v.name], "Dan"))
}

Retrieve Resource in List by Attribute Value

The previous examples show how to use the index() function to look up and retrieve elements from a list by their value, including by the value of an attribute on objects within a list. The later method of list value lookup can be extremely useful when you need to get an object reference from a list of objects managed by a Terraform Provider.

This scenario can be useful to get a single resource reference from a list of resources managed by Terraform using the count or for_each expression to create multiple resource instances using a single block of Terraform code. The following is a simple example of this that retrieves a specific resource and then sets an output variable to the value of the id attribute of the object:

locals {
  subnets = ["public", "default", "private"]
}

resource "azurerm_subnet" "subnet" {
  count = length(local.subnets)
  name = local.subnets[count.index].name
  # other resource attributes here
}

output "default_subnet_id" {
  value = azurerm_subnet.subnet[index(azurerm_subnet.subnet.*.name, "default")].id
}
Microsoft MVP

Chris Pietschmann is a Microsoft MVP (Azure & IoT) and HashiCorp Ambassador (2021) with 20+ years of experience designing and building Cloud & Enterprise systems. He has worked with companies of all sizes from startups to Fortune 100. He is also a Microsoft Certified Azure Solutions Architect and developer, a Microsoft Certified Trainer (MCT), and Cloud Advocate. He has a passion for technology and sharing what he learns with others to help enable them to learn faster and be more productive.