Explaining Count Loop in Terraform

Pavol Kutaj
2 min readNov 27, 2023

--

The aim of this pageđź“ť is to explain count looping constructs in Terraform. Being new to HCL and its declarative nature, this looping construct/meta-argument is initially weird (there is also for_each and dynamic blocks). So, you iterate, but you also assign a value (use =) simultaneously. In addition, your loop is a part of the resource definition, not the other way around.

the count loop is used to create multiple almost identical resources

  • the count takes a positive integer or a 0
  • why 0? because setting count to 0 is a way to condition the creation of a resource
  • the definition syntax is very simple — use the keyword count right after the resource declaration
  • it is possible and often useful to create a dedicated variable that is referred to in the count meta-argument instead of hardcoding the count with a number so that you control the same value used many times from a single place (classical DRY principle)
# DEFINITION 
## SYNTAX
resource "<resource_type>" "<name_label>" {
count = <int>
...
}

## EXAMPLE #1
resource "aws_instance" "web_server" {
count = 3
tags = {
Name = "mrp-web-${count.index}:
}
}

## EXAMPLE #2
resource "aws_lb" "alb" {
count = var.instance_count
...
}

# THE VARIABLE USED THROUGOUHT THE CONFIG
variable "instance count" {
type = number
description = "Number of instances to create"
default = 2
}

there are 3 ways of referring with count: <name>[count.index] — <name>[<int>] — <name>[*]

  • count creates a list of resources
  • the created list is referred by classical indexing syntax using square brackets
  • as terraform loops through items via count, it also creates and iterates over count.index
  • count.index value starts with 0
  • you explicitly use count.index for referring to resources if you are harmonizing count across resources
resource "aws_instance" "nginx" {
count = var.instance_count # <-- DRY
ami = nonsensitive(data.aws_ssm_parameter.amzn2_linux.value)
instance_type = "t2.micro"
}

# aws_lb_target_group_attachment
resource "aws_lb_target_group_attachment" "nginx" {
count = var.instance_count # <-- DRY
target_group_arn = aws_lb_target_group.nginx.arn
target_id = aws_instance.nginx[count.index].id # <--- `count.index` refering to the first resource within larger iteration
port = 80
}
  • what is in the language is the possibility to refer to all instances at once by using a wildcard *
  • …this is a special character returning list of referred values for each instance
  • using * is known as splat syntax
# REFERENCE/INDEXING 
## SYNTAX
<!-- <attribute> is optional -->

<resource_type>.<name_label>[element_index].<attribute>
<resource_type>.<name_label>[*].<attribute>

# REFERENCE EXAMPLE #1
aws_instance.web_server[count.index].name
aws_instance.web_server[0].name
aws_instance.web_server[*].name

# REFERENCE EXAMPLE #2
output "alb_id" {
value = "${var.deploy ? join("", aws_lb.alb.*.id) : ""}"
}

LINKS

--

--

Pavol Kutaj

Today I Learnt | Infrastructure Support Engineer at snowplow.io with a passion for cloud infrastructure/terraform/python/docs. More at https://pavol.kutaj.com