Understanding one() Function in Terraform

Understanding the behavior of Terraform's one() function.

Introduction

Terraform provides a one() function.

Because the naming is so minimal, it wasn’t immediately clear how it behaves, so I’ve organized and summarized it here.

Note: This article was translated from my original post.

Understanding the Behavior of one()

Specification of one()

Quoting from the documentation:

one takes a list, set, or tuple value with either zero or one elements. If the collection is empty, one returns null. Otherwise, one returns the first element. If there are two or more elements then one will return an error.

In other words:

  • The one() function accepts a collection (list, set, tuple) as an argument
  • If the collection is empty, one() returns null
  • If the collection has exactly one element, one() returns that value
  • If the collection has two or more elements, one() returns an error

Simply put, it’s a function that only works on collections with 0 or 1 elements, and if there’s exactly 1 element, it returns that value.

Examples

Here are some actual examples:

# When the collection is empty, one() returns `null`
> one([])
null

> one(toset([]))
null
# When the collection has exactly one element, one() returns that value
> one(["hello"])
"hello"

> one(toset(["hello"]))
"hello"
# When the collection has two or more elements, one() returns an error
> one(["hello", "world"])
╷
│ Error: Invalid function argument
│ 
│   on <console-input> line 1:
│   (source code not available)
│ 
│ Invalid value for "list" parameter: must be a list, set, or tuple value with either zero or one elements.
╵

> one(toset(["hello","world"]))
╷
│ Error: Invalid function argument
│ 
│   on <console-input> line 1:
│   (source code not available)
│ 
│ Invalid value for "list" parameter: must be a list, set, or tuple value with either zero or one elements.

If you pass a collection with two or more elements, you get an error saying it only accepts lists/sets/tuples with zero or one element.

When to Use one()

At first glance, the one() function seems oddly restrictive, but it has clear use cases.

In Terraform, it’s common to use the count parameter to conditionally create resources — for example, creating one resource under certain conditions and none otherwise.

When referencing resources created under such conditional logic, one() is useful.

variable "include_ec2_instance" {
  type    = bool
  default = true
}

resource "aws_instance" "example" {
  count = var.include_ec2_instance ? 1 : 0

  # (other resource arguments...)
}

output "instance_ip_address" {
  value = one(aws_instance.example[*].private_ip)
}

Ref. https://developer.hashicorp.com/terraform/language/functions/one

Here, the count = var.include_ec2_instance ? 1 : 0 line controls whether the resource count is 0 or 1.

By writing one(aws_instance.example[*].private_ip), when one instance is created it returns that instance’s private_ip, and when zero instances are created it returns null.

If we didn’t use one() and instead wrote:

output "instance_ip_address" {
  value = aws_instance.example[0].private_ip
}

it would cause an error when no resources are created (aws_instance.example[0] wouldn’t exist).

Conclusion

We’ve reviewed the behavior of Terraform’s one() function.

By understanding how it works, you can apply it effectively in the right situations.

I hope this helps someone!

[Related Articles]

en.bioerrorlog.work

References