
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:
truefalse
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.
