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. If you're feeding values like is_enabled in from variable files, our guide to tfvars in Terraform and OpenTofu covers how that works.

Sign Up and get started by using Scalr today.

Frequently asked questions

How do conditional statements work in Terraform?

Terraform has one main conditional expression, the ternary operator. It has three parts: a test expression, a value returned when the test is true, and a value returned when it is false. Both possible return values must be the same type. There is also an if clause you can use inside a for expression to filter collections.

How do I conditionally create a resource in Terraform?

Put a ternary expression on the resource's for_each meta-argument. When a boolean variable is true, return a map like { enabled = true } so one instance is created; when it is false, return an empty map so nothing is created. You can do the same with count, but that approach is less recommended.

Can you nest ternary expressions in Terraform?

Yes. You can nest ternary expressions to check multiple conditions, for example picking a different VM size for each environment. Every condition you add makes the code harder to read and more brittle, so avoid nesting unless you have no other option.

What does the if clause in a Terraform for expression do?

The if clause filters a collection before the for expression returns it, such as keeping only map entries whose key matches an input variable. It cannot check whether a property or field exists on an object; that returns an error. It is less capable than the ternary operator but still useful for filtering data.
About the author
Brendan Thompsonsolutions engineer at Scalr
Brendan Thompson is a solutions engineer at Scalr, specializing in Terraform and cloud infrastructure.