Table of Contents
Terraform Conditional Arguments and Dynamic Blocks
Summary: This wiki page shows how I used terraform's conditionals in arguments and dynamic blocks to make configurations more flexible by showing a few examples.
Date: 1 January 2026
Conditionals and dynamic blocks are terraform features you usually don't need when you're just starting. Their power comes when you're starting to work on more complex terraform configurations or modules. Below I show a couple of examples where I used conditionals and dynamic blocks. For both features, you always need to consider if using them is really the best solution for your problem. I've often encountered that using for example default values and optional arguments can solve the same problem in a more straightforward way.
Conditionals
I usually use terraform conditionals to optionally include certain arguments in a resource or a module.
Conditional Resource Creation
My most used example of using conditionals is to conditionally create resources based on a boolean variable. In the example below, taken from my PostgreSQL module, I only create a Private DNS Zone if the variable `deploy_psql_pep` is set to true:
module "avm-res-network-privatednszone" {
count = var.deploy_psql_pep == true ? 1 : 0
source = "Azure/avm-res-network-privatednszone/azurerm"
domain_name = var.privatezone
parent_id = module.avm-res-resources-resourcegroup.resource_id
tags = var.tags
enable_telemetry = false
}
Conditional Arguments
Another use case is to conditionally include certain arguments in a resource or a module. For example, in the code snippet below, I use a conditional argument to only include the `law_id` argument if the variable `deploy_psql_logs` is set to true. If it's false, the argument is set to null and will be ignored by terraform.
law_id = var.deploy_psql_logs ? module.law.id : null
This is another example where I use conditional arguments to only enable cross-region restore if the redundancy is set to GeoRedundant and the variable `cross_region_restore_enabled` is true:
cross_region_restore_enabled = var.redundancy == "GeoRedundant" && var.cross_region_restore_enabled ? true : null
Conditional Argument Values
In the example below, I set the value to a certain argument based on the value of a variable:
# Required for restore scenarios create_mode = var.create_mode # Set to null if empty string. Only required when using create_mode of Restore or Recovery recover_database_id = var.recover_database_id == "" ? null : var.recover_database_id recovery_point_id = var.recovery_point_id == "" ? null : var.recovery_point_id
Dynamic Blocks
Dynamic blocks are another way of making terraform configurations more flexible. They also have different use cases.
Repeat for each Object in a List
Below is an example where dynamic blocks are used to repeat a block for each object in a list. The variable backup_vault_blobstorage_policies has a list of policy_retention_rules objects. In the resource definition, a dynamic block is used to create a retention_rule block for each object in that list.
# Variable backup_vault_blobstorage_policies = [ { policy_name = "bkpol-euw-shift" policy_repeating_time_intervals = ["R/2025-01-01T04:00:00Z/P1D"] policy_default_vault_retention_duration = "P5D" policy_data_store_type = "VaultStore" policy_retention_rules = [ { rule_name = "Yearly" rule_retention_duration = "P1Y" rule_priority = 1 absolute_criteria = "FirstOfYear" }, { rule_name = "Monthly" rule_retention_duration = "P1M" rule_priority = 5 absolute_criteria = "FirstOfMonth" }, { rule_name = "Weekly" rule_retention_duration = "P1W" rule_priority = 10 absolute_criteria = "FirstOfWeek" }, { rule_name = "Daily" rule_retention_duration = "P2D" rule_priority = 15 absolute_criteria = "FirstOfDay" } ] } ] # Resource resource "azurerm_data_protection_backup_policy_blob_storage" "bkpol" { for_each = { for policy in var.backup_vault_blobstorage_policies : policy.policy_name => policy } name = each.key vault_id = azurerm_data_protection_backup_vault.bvault.id backup_repeating_time_intervals = each.value.policy_repeating_time_intervals vault_default_retention_duration = each.value.policy_default_vault_retention_duration dynamic "retention_rule" { for_each = each.value.policy_retention_rules content { name = retention_rule.value.rule_name priority = retention_rule.value.rule_priority criteria { absolute_criteria = retention_rule.value.absolute_criteria } life_cycle { data_store_type = each.value.policy_data_store_type duration = retention_rule.value.rule_retention_duration } } } }
Conditionally add Dynamic Blocks to a Resource
In the example below, the variable only defines the retention_daily and retention_weekly objects. In the resources definition, because the retention_monthly and retention_yearly objects are not defined, these rules will not be created.
# Variable recovery_vault_policies_vms = [ { policy_name = "rsvpol-euw-shift" backup_frequency = "Daily" timezone = "UTC" instant_restore_retention_days = 7 backup_time = "02:00" retention_daily = { count = 8 } retention_weekly = { count = 2 weekdays = ["Wednesday"] } instant_restore_resource_group_prefix = "rg-euw-shift-azurebackup-" } ] # Resource resource "azurerm_backup_policy_vm" "rsvpol_vm" { for_each = { for policy in var.recovery_vault_policies_vms: policy.policy_name => policy } name = each.key resource_group_name = var.resource_group_name policy_type = "V2" recovery_vault_name = azurerm_recovery_services_vault.rsvault.name timezone = each.value.timezone instant_restore_retention_days = each.value.instant_restore_retention_days backup { frequency = each.value.backup_frequency time = each.value.backup_time } dynamic "retention_daily" { for_each = each.value.retention_daily != null ? [each.value.retention_daily] : [] content { count = lookup(retention_daily.value, "count") } } dynamic "retention_weekly" { for_each = each.value.retention_weekly != null ? [each.value.retention_weekly] : [] content { count = lookup(retention_weekly.value, "count") weekdays = lookup(retention_weekly.value, "weekdays") } } dynamic "retention_monthly" { for_each = each.value.retention_monthly != null ? [each.value.retention_monthly] : [] content { count = lookup(retention_monthly.value, "count") weekdays = lookup(retention_monthly.value, "weekdays") weeks = lookup(retention_monthly.value, "weeks") } } dynamic "retention_yearly" { for_each = each.value.retention_yearly != null ? [each.value.retention_yearly] : [] content { count = lookup(retention_yearly.value, "count") weekdays = lookup(retention_yearly.value, "weekdays") weeks = lookup(retention_yearly.value, "weeks") months = lookup(retention_yearly.value, "months") } } instant_restore_resource_group { prefix = each.value.instant_restore_resource_group_prefix } }
For completeness, as some of the blocks are not required, this is the variable definition:
variable "recovery_vault_policies_vms" { description = "(Required) The list of Recovery Vault Policies. Note that the instant_restore_retention_days MUST be lower than the retention_daily count." type = list(object({ policy_name = string default_policy = optional(bool, false) timezone = string instant_restore_retention_days = number backup_frequency = string backup_time = string retention_daily = optional(object({ count = number }), null) retention_weekly = optional(object({ count = number weekdays = list(string) }), null) retention_monthly = optional(object({ count = number weekdays = list(string) weeks = list(string) }), null) retention_yearly = optional(object({ count = number weekdays = list(string) weeks = list(string) months = list(string) }), null) instant_restore_resource_group_prefix = string })) }
Conditionally add Dynamic Blocks to a Resource II
In the example below another use case is displayed for combining conditionals and dynamic blocks. In the example below, Entra ID permissions need to be assigned to a storage account fileshare. For this, the file share first needs to be configured and added to Active Directory. For that purpose, a condition is added that is dependent on the variable azure_files_authentication_enabled. This variable can first be set to false, and once the share is added and the required information is known, the variable can be set to true to add the block to the resource.
# Variables azure_files_authentication_enabled = true azure_storage_sid = "S-1-5-21-c07042a510-976c1cfc35-109e3ee4cb-59734" # Resource resource "azurerm_storage_account" "storage_account" { name = var.storage_account_name resource_group_name = var.resource_group_name location = var.location account_tier = var.account_tier account_replication_type = var.replication_type allow_nested_items_to_be_public = var.allow_nested_items_to_be_public tags = var.tags dynamic "azure_files_authentication" { for_each = var.azure_files_authentication_enabled ? [1] : [] content { directory_type = "AD" active_directory { domain_name = "getshifting.local" domain_guid = "446b774a-fd85-424d-947f-6cd03c26a57d" domain_sid = "S-1-5-21-c07042a510-67a1a4512-5974e28db3" forest_name = "getshifting.local" storage_sid = var.azure_storage_sid netbios_domain_name = "getshifting.local" } } } }
This wiki has been made possible by:
