TrademarkTrademark
Features
Documentation

Understand Conditional Statements in Terraform in 5 minutes

Learn how to use conditional statements in 5 minutes
Brendan ThompsonOctober 6, 2023
Understand Conditional Statements in Terraform in 5 minutes
Key takeaways
  • Terraform's main conditional is the ternary operator, with a test expression, a truthful expression, and a false expression, where both return values must be the same type.
  • A ternary on for_each can feature-flag a resource: a true condition returns a map so one resource is created, while false returns an empty map and creates nothing.
  • Ternary expressions can select values like resource size by environment and can be nested, though nesting makes code harder to read and more brittle.
  • The if clause inside a for expression filters collection data before returning it, but cannot check for the existence of a property on an object.

The Terraform documentation says there is only one kind of conditional expression, the ternary operator. There is also an if expression you can use inside a for expression. This post covers both, and how to make Terraform do something conditionally with each.

Start with the ternary operator. The right hand side of the expression has three parts:

  • The test expression — the conditions we are using to test truthfulness
  • The truthful expression — what is returned if the condition is true
  • The false expression — what is returned if the condition is false

An image visually explaining the concepts of conditional expressions.

That covers a lot of ground. You can check whether something has a value, or build up a larger test, like confirming that several resources exist in a network or hold the right permissions before you act on them.

NOTE — Return Types: Both sides of the ternary expression itself MUST be the same type.

Here is an example where we use the conditional as a way to feature-flag a Terraform resource.

variable "is_enabled" {
  type        = bool
  description = <<-DESC
    (Optional) Should feature be enabled
    [Default: `false`]
  DESC
  default = false
}
resource "scratch_string" "first" {
  in = "I am the first"
}
resource "scratch_string" "second" {
  for_each = var.is_enabled ? { enabled = true } : {}
  in = "I am the second"
}

First a variable is declared (is_enabled) which will be used to understand if the second string should be created or not. This works because if is_enabled is true then { enabled = true } is returned to the for_each and a single resource will be created, however if it is false then an empty map ({}) will be returned which yields no resource creation. This same result can be achieved utilising the count meta-argument however this is less recommended.

You can use these almost anywhere in Terraform. Here is another example:

resource "azurerm_linux_virtual_machine" "this" {
 # ...
 size = var.environment == "prd" ? "Standard_D32d_v5" : "Standard_D2d_v5"
 # ...
}

Here we create a virtual machine that is much more powerful in production than anywhere else. You can also nest these expressions to check more conditions, though you should avoid that unless you have no other option.

resource "azurerm_linux_virtual_machine" "this" {
 # ...
 size = var.environment == "prd" ? "Standard_D32d_v5" : (
 var.environment == "ppd" ? "Standard_D16d_v5" : (
 var.environment == "uat" ? "Standard_D8d_v5" : "Standard_D2d_v5"
 )
 )
 # ...
}

You can see that every condition you add makes the code harder to read and more brittle. It is possible, though.

Any part of the expression can be wrapped in parentheses (()), which lets you combine multiple checks or build a return value from a more complex expression. In the test expression, for example, you might want to confirm several things are all true with the alltrue() function.

The second conditional type is the if inside a for expression. Here is how it works.

locals {
 animals = {
 	mammal = {
 		feline = {
 			name = "cat"
 			sound = "meow"
 		}
 		canine = {
 			name = "dog"
 			sound = "woof"
 		}
	 }
 reptile = {
 serpentes = {
 name = "snake"
 sound = "hiss"
 }
 }
 }
}
variable "class" {
 type = string
 default = "mammal"
}
resource "scratch_string" "first" {
 for_each = {
 for k, v in local.animals :
 k => v
 if k == var.class
 }
 in = each.key
}

Here we filter the animals by their class, which comes in through an input variable. The for expression can do much more, especially in how it returns data, but that is outside the scope of this post. We are focused on the if. One thing to watch: you cannot use the if inside a for to check whether a property or field exists on an object, since that returns an error. The if is not as capable as the ternary operator, but it still does a lot.

We covered the ternary operator, which returns one value or another based on a condition. It lets you decide things like the size of a resource per environment, or whether a resource gets created at all. We also covered the if on a for expression, which filters data before it gets returned. Both are worth reaching for in your own Terraform code.

Sign Up and get started by using Scalr today.

About the author
Brendan Thompsonsolutions engineer at Scalr
Brendan Thompson is a solutions engineer at Scalr, specializing in Terraform and cloud infrastructure.