Is it possible to set attribute defaults in a list of objects?

My scenario: I want to create three instances, with one in a different subnet.
My variable is set like this:

variable "instances" {
    type = list(object({
        name = string
        type = string
        subnet = string
    }))

    default = [
        {
        name = ""
        type = ""
        subnet = "DefaultSubnet"
    }]
}

and defined in a tfvars file like this:

instances = [ 
  {
  name = "PRInstace"
  type = "PR"
} ,
{
  name = "UTInstance"
  type = "UT"
} ,
{
  name = "DBInstance"
  type = "DB"
  subnet = "DBSubnet"
} ,
]

But when I run Terraform plan, I get this result:

Error: Invalid value for input variable
│
│   on instances.auto.tfvars line 23:
│   23: instances = [ 
│   24:   {
│   25:   name = "PRInstace"
│   26:   type = "PR"
│   27: } ,
│   28: {
│   29:   name = "UTInstance"
│   30:   type = "UT"
│   31: } ,
│   32: {
│   33:   name = "DBInstance"
│   34:   type = "DB"
│   35:   subnet = "DBSubnet"
│   36: } ,
│   37: ]
│
│ The given value is not suitable for var.instances declared at variables.tf:23,1-21: element 0: attribute "subnet" is required.

The only way to get around this is to define the subnet explicitly for each object. But that would defeat the purpose for a default at all. I want it to, well, default to the default value when I don’t define it - not require it when I don’t have it.

Is there a way to make this work? Or perhaps its not possible to set default values for attributes in a list of objects?

Update: it appears I found the answer. Using the optional function on the subnet attribute when defining the variable:

variable "instances" {
    type = list(object({
        name = string
        type = string
        subnet = optional(string)
    }))

    default = [
        {
        name = ""
        type = ""
        subnet = "defaultsubnet"
    }]
}

EDIT: no, this didn’t work, it gave ALL the instances the DBSubnet.

I think it’s likely that you’ll want to specify in-line defaults (using Terraform 1.3 or later), as follows:

variable "instances" {
    type = list(object({
        name = string
        type = string
        subnet = optional(string, "defaultsubnet")
    }))
    default = []
}

This way the defaults are applied to each element of the list, and the default value for the list (if no value is specified) is an empty list.

1 Like

Yes, I found out after posting above that currently it gave ALL the instances the “DBSubnet” instead of the “DefaultSubnet”
After setting it as you suggested, it worked correctly - and I was able to get rid of the default block entirely.

variable "instances" {
    type = list(object({
        name = string
        type = string
        subnet = optional(string, "defaultsubnet")
    }))
}