Terraform
Terraform
October 20, 2022

Terraform Optionals On Complex Input Variables

By
Brendan Thompson

With the recent release of Terraform v1.3 we were given one of the most - in my opinion - important features to come to Terraform since the v1.0 release. And that is, the optional object type attribute. To first understand why this is so powerful let's look at a variable for creating a storage account on Azure.

The variables will be at their rawest form, no validation or description.

variable "storage_account" {
type = object({
  name                = string
  resource_group_name = string
  location            = string
  kind                = string
  tier                = string
  replication_type    = string
  })
}

This above example has all the properties we need to create a storage account on Azure, however, the kind property is actually optional and given that optional on an attribute doesn't exist yet, we will need to deal with that. There were two ways that I have seen commonly used:

storage_account = {
  name                = "sablt"
  resource_group_name = "rg-blt"
  location            = "australieast"
  kind                = "" //NOTE: We don't want to set this
  tier                = "Premium"
  replication_type    = "LRS"
}

This is what we would set either in a .tfvars file or a module call. We are passing in an empty string on kind and our code would deal with the occurrence of an empty string for us, but we still have to type those four pesky characters. So lets look at the next scenario, which actually requires more typing!

variable "storage_account" {
  type = object({
    name                = string
    resource_group_name = string
    location            = string
    tier                = string
    replication_type    = string
  })
}

variable "storage_account_kind" {
  type    = string
  default = ""
}

Now we have two variables, and this could be worse and that entire storage_account variable could be split out into its individual components. And yes, I have seen that happen. We have also set a default for the variable so that we don’t ever have to pass anything in if we don’t want/need to.

On the surface I would say this doesn’t feel so bad, especially when its something rather simple like this. But, if you were to extrapolate this to more complex situations or were there are many - potentially most - optional properties you are going to end up with a mess of variables. I personally always opt for complex objects as I feel it is far easier to see and understand what’s going on and what the requirements of the code are!

Now, lets move on to the fun stuff! Lets use this awesome new feature!

variable "storage_account" {
  type = object({
    name                = string
    resource_group_name = string
    location            = string
    kind                = optional(string)
    tier                = string
    replication_type    = string
  })
}

Above we can now see the kind is of type optional(string) this means that should we desire to set a value that value will be a string. It can go a step further though. What if we wanted to set a default value just for this property, well now you can!

variable "storage_account" {
  type = object({
    name                = string
    resource_group_name = string
    location            = string
    kind                = optional(string, "StorageV2")
    tier                = string
    replication_type    = string
  })
}

We probably aren’t going to set a default value for this particular property as we more so want it to be optional, but the tier for instance we might want to default to something that is common for the business and you deviate from it on an as needs basis.

optional gives us as engineers a huge amount of power to setup our complex object variables now, set sensible defaults and fully optional for some properties. No longer will we be required to build out seperate variables for properties we want to be optional.

You can follow Brendan @BrendanLiamT on Twitter.

Note: While this blog references Terraform, everything mentioned in here also applies to OpenTofu. New to OpenTofu? It is a fork of Terraform 1.5.7 as a result of the license change from MPL to BUSL by HashiCorp. OpenTofu is an open-source alternative to Terraform that is governed by the Linux Foundation. All features available in Terraform 1.5.7 or earlier are also available in OpenTofu. Find out the history of OpenTofu here.

Start using the Terraform platform of the future.

A screenshot of the modules page in the Scalr Platform