Learn how to define and use optional nested object variables in Terraform to create flexible and reusable infrastructure configurations.
In Terraform, defining optional nested objects with default values ensures flexibility and avoids configuration errors. This approach allows you to specify default values for nested attributes, which are applied if the user doesn't provide them. This guide outlines the steps to define optional nested objects with defaults in Terraform, enabling you to create adaptable and robust infrastructure configurations.
To define optional nested objects with defaults in Terraform, follow these steps:
Define the variable with its type as an object:
variable "example" {
type = object({
nested_field = object({
optional_value = string
})
})
}
Set default values, including for nested attributes:
variable "example" {
type = object({
nested_field = object({
optional_value = string
})
})
default = {
nested_field = {
optional_value = "default value"
}
}
}
Use the optional()
function for conditional defaults within nested objects:
variable "example" {
type = object({
nested_field = optional(object({
optional_value = string
}), {
optional_value = "default value"
})
})
}
Access nested values using dot notation:
resource "example_resource" "example" {
# ... other configurations ...
optional_value = var.example.nested_field.optional_value
}
Important Considerations:
null
overrides any default values.optional()
, the entire nested object will be set to the default if not provided.This code defines a Terraform variable "example" with an optional nested object "nested_field". The nested object has default values for its fields "optional_value" and "another_optional_value". The main.tf file uses a null_resource to demonstrate accessing and printing these values. Users can provide the "example" variable with custom values, partially or entirely, or rely on the defined defaults. This allows for flexible configuration with optional nested objects and default values in Terraform.
This example demonstrates how to define and use optional nested objects with default values in Terraform.
variables.tf
variable "example" {
type = object({
nested_field = optional(object({
optional_value = string
another_optional_value = number
}), {
optional_value = "default string value"
another_optional_value = 123
})
})
}
main.tf
resource "null_resource" "example" {
provisioner "local-exec" {
command = <<EOT
echo "Optional Value: ${var.example.nested_field.optional_value}"
echo "Another Optional Value: ${var.example.nested_field.another_optional_value}"
EOT
}
}
Explanation:
variables.tf:
example
with a nested object structure.nested_field
is declared as optional using the optional()
function.optional()
, we define the object structure for nested_field
and provide default values for optional_value
and another_optional_value
.main.tf:
null_resource
with a local-exec
provisioner for demonstration purposes.optional_value
and another_optional_value
from the example
variable.Usage:
Without providing any input: The default values defined in variables.tf
will be used.
Providing partial input: You can provide only specific nested values, and the remaining ones will use their defaults. For example:
example = {
nested_field = {
optional_value = "custom value"
}
}
Overriding default values: You can explicitly set a value to null
to override the default.
Output:
When running Terraform, the output will display the values used for optional_value
and another_optional_value
, either the defaults or any custom values provided.
This example demonstrates how to effectively manage optional nested objects with default values in Terraform, allowing for flexible and reusable configurations.
Best Practices:
Common Pitfalls:
optional()
: While convenient, overusing optional()
can make it harder to track which values are truly optional and which are expected. Use it judiciously.Alternatives to Nested Objects:
Additional Tips:
By understanding these concepts and following best practices, you can leverage the power of optional nested objects with defaults to create flexible, maintainable, and robust Terraform configurations.
This table summarizes how to define and use optional nested objects with default values in Terraform:
Step | Description | Code Example |
---|---|---|
1. Define Variable Type | Define the variable and its type as an object, including nested objects. | ```terraform |
variable "example" { |
type = object({
nested_field = object({
optional_value = string
})
})
}
| 2. Set Default Values | Set default values for the variable, including nested attributes. | ```terraform
variable "example" {
// ... type definition ...
default = {
nested_field = {
optional_value = "default value"
}
}
}
``` |
| 3. Use `optional()` Function | Use the `optional()` function for conditional defaults within nested objects. This sets the entire nested object to the default if not provided. | ```terraform
variable "example" {
type = object({
nested_field = optional(object({
optional_value = string
}), {
optional_value = "default value"
})
})
}
``` |
| 4. Access Nested Values | Access nested values within resources using dot notation. | ```terraform
resource "example_resource" "example" {
// ... other configurations ...
optional_value = var.example.nested_field.optional_value
}
``` |
**Key Considerations:**
* **Default Application:** Terraform applies defaults top-down (parent defaults first).
* **Null Values:** Explicitly setting a value to `null` overrides any default values.
* **Complex Scenarios:** Use modules to organize and reuse variable definitions for complex scenarios.
## Conclusion
By combining these techniques, you can create adaptable and well-structured Terraform configurations. Remember to prioritize clarity, document your code thoroughly, and test your configurations to ensure they behave as expected. This approach empowers you to leverage the flexibility of optional nested objects while maintaining predictable and manageable infrastructure deployments.
## References
* ![Default (optional) values in nested null object cause it to be non-null ...](https://opengraph.githubassets.com/a7f1a2746b496de3e4fffd16292a9d0e114743f7f653d6661d3833ae6fd52ec6/hashicorp/terraform/issues/32160) [Default (optional) values in nested null object cause it to be non-null ...](https://github.com/hashicorp/terraform/issues/32160) | Terraform Version Terraform v1.3.4 Terraform Configuration Files module "defaulting_module" { source = "./modules/default-module" request = {} } output "output" { value = module.defaulting_module }...
* ![Type Constraints - Configuration Language | Terraform | HashiCorp ...](https://developer.hashicorp.com/og-image/terraform.jpg) [Type Constraints - Configuration Language | Terraform | HashiCorp ...](https://developer.hashicorp.com/terraform/language/expressions/type-constraints) | Terraform applies object attribute defaults top-down in nested variable types. ... optional modifier first and then later applies any nested default values ...
* ![[Request] module_variable_optional_attrs: Optional nested maps ...](https://opengraph.githubassets.com/b9787c01700cefb15938a2b4efd10f36c65b37f9db1db1b66b6e9702ebc09925/hashicorp/terraform/issues/27613) [[Request] module_variable_optional_attrs: Optional nested maps ...](https://github.com/hashicorp/terraform/issues/27613) | Current Terraform Version 0.14.6 Use-cases I have a complex module. I would like to allow my end-users to be able to group like-variables together — specifically as a nested object/map. I'm looking...
* ![Required attributes in nested object - Terraform - HashiCorp Discuss](https://global.discourse-cdn.com/hashicorp/original/1X/154331ed085112b536f7a0c4c5355c17a57e53c1.png) [Required attributes in nested object - Terraform - HashiCorp Discuss](https://discuss.hashicorp.com/t/required-attributes-in-nested-object/23854) | Hi, I’m currently using the Terraform 0.13.5 and fairly new to the product. // variables.tf in a module variable "foo" = { description = "Demo" type = object({ foo1 = string foo2 = object({ foo2_1 = string // Optional foo2_2 = bool // Optional }) foo3 = object({ foo3_1 = number // Required value foo3_2 = string ...
* ![Terraform “dynamic” inside “dynamic” blocks — an implementation ...](https://miro.medium.com/v2/resize:fit:1200/1*sCQP6zeuPgyi_Kke5rs0Vw.png) [Terraform “dynamic” inside “dynamic” blocks — an implementation ...](https://medium.com/@adrianarba/terraform-dynamic-inside-dynamic-blocks-an-implementation-example-c129f62135bb) | Sometimes, to tackle seemingly easy tasks, one needs to venture into uncharted territory to find a solution.
* ![Request for Feedback: Optional object type attributes with defaults in ...](https://global.discourse-cdn.com/hashicorp/original/1X/154331ed085112b536f7a0c4c5355c17a57e53c1.png) [Request for Feedback: Optional object type attributes with defaults in ...](https://discuss.hashicorp.com/t/request-for-feedback-optional-object-type-attributes-with-defaults-in-v1-3-alpha/40550?page=3) | An important distinction to be made here is that an explicitly set null value can only be determined at the syntax level, not within the language in general. This means when assigning nested objects to types with defaults, nested unset attributes will inherently have a null value and therefore we need to decide whether those will get a default or not. The choice is somewhat arbitrary, but a choice needs to be made nonetheless, and it’s consistent with the definition of the Terraform language to ...
* ![Terraform — Optional Values. A quick article discussing the options ...](https://miro.medium.com/v2/resize:fit:678/0*bcpwamyNyz160CR3.png) [Terraform — Optional Values. A quick article discussing the options ...](https://danielrandell93.medium.com/terraform-optional-values-73407f1d5ce5) | A quick article discussing the options for having optional values in your variables in Terraform.
* ![Nested optional() vars question - Terraform - HashiCorp Discuss](https://global.discourse-cdn.com/hashicorp/original/1X/154331ed085112b536f7a0c4c5355c17a57e53c1.png) [Nested optional() vars question - Terraform - HashiCorp Discuss](https://discuss.hashicorp.com/t/nested-optional-vars-question/51877) | Greetings, I have this variable "druid_cluster" { description = "Druid cluster" type = map(map(object({ instance_type = string private_ip = string root_block_device = optional(list(map(object({ encrypted = bool volume_type = string volume_size = number tags = list(string) }))), [{ encrypted = true volume_type = "gp2" volume_size = 512 tags = { some = "tag"} }]) }))) default = {} } I’m trying to get it work. ...
* ![Best practices for setting default values for objects : r/Terraform](https://share.redd.it/preview/post/vkkitq) [Best practices for setting default values for objects : r/Terraform](https://www.reddit.com/r/Terraform/comments/vkkitq/best_practices_for_setting_default_values_for/) | Posted by u/greenlakejohnny - 15 votes and 26 comments