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 a bigger test, like confirming that several resources exist in a network or have the right permissions before you act on them.

NOTE on 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 we declare a variable (is_enabled) that decides whether the second string gets created. It works like this: if is_enabled is true, then { enabled = true } goes to the for_each and you get one resource. If it's false, you get an empty map ({}) and nothing is created. You can do the same thing with the count meta-argument, but that's 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.

You can wrap any part of the expression in parentheses (()), which lets you combine multiple checks or build a return value from a more complicated 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 a lot more, especially in how it returns data, but that's outside the scope of this post. We're focused on the if. One thing to watch: you can't use the if inside a for to check whether a property or field exists on an object, since that returns an error. The if isn't as capable as the ternary operator, but it still does a lot.

So that's 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 looked at 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.