How to Output Resources with `count` in Terraform

This post explains how to output a resource in Terraform when its creation is controlled using the count parameter.

Introduction

In Terraform, the count parameter lets you control how many instances of a resource are created.

By using this, you can conditionally create resources based on external input—often by switching between 0 and 1.

resource "aws_ecr_repository" "this" {
  name  = "example"
  count = var.create ? 1 : 0
}

However, when trying to output a resource controlled with count, it's not immediately obvious how to write it:

output "aws_ecr_repository" {
  value = aws_ecr_repository.this[0] ## ???
}

This post walks through the ways to handle this.

Note: This article was translated from my original post.

Outputting Resources Controlled by count

The source code used for this post is available here:

github.com

Method 1: Use the one Function

variable "create" {
  description = "Controls if ECR resources should be created"
  type        = bool
  default     = true
}

resource "aws_ecr_repository" "this" {
  name  = "example"
  count = var.create ? 1 : 0
}

output "aws_ecr_repository" {
  value = one(aws_ecr_repository.this[*])
}

The one function works with collections of either 0 or 1 element and returns the element if it exists.

This lets you output the resource only if it was created. If not, null will be returned.

See also: Understanding one() Function in Terraform - BioErrorLog Tech Blog (en)


Example behavior:

If the resource is created, the output will contain the full resource object:

Outputs:

aws_ecr_repository = {
  "arn" = "arn:aws:ecr:ap-northeast-1:<account_id>:repository/create_example_ecr"
  "encryption_configuration" = tolist([
    {
      "encryption_type" = "AES256"
      "kms_key" = ""
    },
  ])
  "force_delete" = tobool(null)
  "id" = "create_example_ecr"
  "image_scanning_configuration" = tolist([
    {
      "scan_on_push" = false
    },
  ])
  "image_tag_mutability" = "MUTABLE"
  "name" = "create_example_ecr"
  "registry_id" = "<account_id>"
  "repository_url" = "<account_id>.dkr.ecr.ap-northeast-1.amazonaws.com/create_example_ecr"
  "tags" = tomap(null) /* of string */
  "tags_all" = tomap({})
  "timeouts" = null /* object */
}


If the resource is not created, the output becomes null:

Changes to Outputs:
  - aws_ecr_repository = {
      - arn                          = "arn:aws:ecr:ap-northeast-1:<account_id>:repository/create_example_ecr"
      - encryption_configuration     = [
          - {
              - encryption_type = "AES256"
              - kms_key         = ""
            },
        ]
      - force_delete                 = null
      - id                           = "create_example_ecr"
      - image_scanning_configuration = [
          - {
              - scan_on_push = false
            },
        ]
      - image_tag_mutability         = "MUTABLE"
      - name                         = "create_example_ecr"
      - registry_id                  = "<account_id>"
      - repository_url               = "<account_id>.dkr.ecr.ap-northeast-1.amazonaws.com/create_example_ecr"
      - tags                         = null
      - tags_all                     = {}
      - timeouts                     = null
    } -> null

Method 2: Use the try Function

variable "create" {
  description = "Controls if ECR resources should be created"
  type        = bool
  default     = true
}

resource "aws_ecr_repository" "this" {
  name  = "example"
  count = var.create ? 1 : 0
}

output "aws_ecr_repository" {
  value = try(aws_ecr_repository.this[0], {})
}

The try function returns the first argument if it's valid, otherwise returns the second one.

In this case, if the resource is created, it will be returned. If not (and accessing aws_ecr_repository.this[0] fails), it falls back to the second argument—an empty object {}.


Example behavior:

If the resource is created:

Outputs:

aws_ecr_repository = {
  "arn" = "arn:aws:ecr:ap-northeast-1:<account_id>:repository/create_example_ecr"
  "encryption_configuration" = tolist([
    {
      "encryption_type" = "AES256"
      "kms_key" = ""
    },
  ])
  "force_delete" = tobool(null)
  "id" = "create_example_ecr"
  "image_scanning_configuration" = tolist([
    {
      "scan_on_push" = false
    },
  ])
  "image_tag_mutability" = "MUTABLE"
  "name" = "create_example_ecr"
  "registry_id" = "<account_id>"
  "repository_url" = "<account_id>.dkr.ecr.ap-northeast-1.amazonaws.com/create_example_ecr"
  "tags" = tomap(null) /* of string */
  "tags_all" = tomap({})
  "timeouts" = null /* object */
}


If not created:

Outputs:

aws_ecr_repository = {}

Conclusion

This post explained how to output resources that are conditionally created using count in Terraform.

By using functions like one and try, you can write cleaner and more reliable Terraform code.

Hope this helps someone out there.

[Related Articles]

en.bioerrorlog.work

References