Azure Bicep is a domain-specific language (DSL) for deploying Azure resources declaratively. One common requirement in infrastructure-as-code is the ability to handle optional or nullable parameters, especially arrays. Making an array nullable allows templates to be more flexible and reusable, accommodating scenarios where certain configurations may or may not be provided.
The most effective way to make an array nullable in Bicep is by defining the parameter with a union type that includes `null`. This approach explicitly states that the parameter can either be an array of a specific type or `null`. Here's how you can achieve this:
param myNullableArray (string[] | null) = null
In this declaration:
myNullableArray
is the parameter name.string[] | null
specifies that the parameter can be either an array of strings or null.= null
sets the default value to null, making the parameter optional.Alternatively, you can declare the parameter as optional by using the `?` suffix. This implicitly allows the parameter to be null if not provided.
param myOptionalArray array? = null
Here, the `?` indicates that `myOptionalArray` is optional and can be omitted, defaulting to null.
Once you've declared a parameter as nullable, it's essential to handle its null state within your Bicep code to avoid runtime errors. Conditional logic allows you to differentiate between a provided array and a null value.
var finalArray = myNullableArray != null ? myNullableArray : ['defaultValue']
This statement assigns `finalArray` to `myNullableArray` if it's not null; otherwise, it assigns a default array.
Bicep provides several functions to manage nullable arrays effectively:
The `coalesce` function returns the first non-null value from its arguments.
var processedArray = coalesce(myNullableArray, [])
This assigns an empty array to `processedArray` if `myNullableArray` is null.
The `empty` function checks whether an array is empty or null.
if (!empty(myNullableArray)) {
// Use myNullableArray
}
This condition checks if `myNullableArray` is neither null nor empty before proceeding.
The safe-dereference operator `?.` allows you to access properties of a potentially null object without causing runtime errors.
var arrayLength = myNullableArray?.length ?? 0
This retrieves the length of `myNullableArray` if it's not null; otherwise, it defaults to `0`.
While allowing null values provides flexibility, defaulting to empty arrays (`[]`) is often more reliable. This approach minimizes the risk of unexpected null values causing deployment failures.
param myArray array = []
Setting the default to an empty array ensures that the parameter always contains an array, even if no values are provided.
Incorporate fallback logic to handle scenarios where the array might be null or empty. This ensures your templates remain robust and handle different deployment scenarios gracefully.
var finalArray = coalesce(myNullableArray, ['fallbackValue'])
This ensures that `finalArray` always has a value, either from `myNullableArray` or a predefined fallback.
To enhance type safety, define union types that specify the array's element types alongside `null`. This ensures that when an array is provided, it adheres to the expected structure.
param myObjectArray (object[] | null) = null
This declaration allows `myObjectArray` to be either an array of objects or null, enforcing structure when values are provided.
In complex templates, you might have multiple nullable array parameters. It's crucial to handle each appropriately to maintain consistency and reliability.
param firstArray (string[] | null) = null
param secondArray (int[] | null) = null
var combinedArray = [
... (firstArray ?? [])
... (secondArray ?? [])
]
This combines `firstArray` and `secondArray`, defaulting to empty arrays if either is null.
Assigning `null` directly to parameters without handling can lead to deployment failures. Always implement checks or defaults to mitigate this risk.
Declaring parameters as optional but not handling their null state can cause unexpected behavior. Ensure that your template logic accounts for scenarios where these parameters are omitted.
When defining union types, neglecting to specify element types can reduce type safety, making your templates more error-prone. Always define clear and specific types for union parameters.
Here's a practical example demonstrating how to define and handle a nullable array parameter in a Bicep template:
param storageAccountNames (string[] | null) = null
var finalStorageAccounts = coalesce(storageAccountNames, [
'defaultStorage1'
'defaultStorage2'
])
resource storageAccounts 'Microsoft.Storage/storageAccounts@2021-04-01' = [for name in finalStorageAccounts: {
name: name
location: resourceGroup().location
kind: 'StorageV2'
sku: {
name: 'Standard_LRS'
}
}]
This template:
Sometimes, you may want to conditionally deploy resources based on whether an array is provided. Here's how to achieve this:
param optionalArray (string[] | null) = null
resource optionalResource 'Microsoft.Example/resource@2021-01-01' = if (!empty(optionalArray)) {
name: 'optionalResource'
properties: {
items: optionalArray
}
}
This template deploys `optionalResource` only if `optionalArray` is not null or empty.
In scenarios where you're certain that a nullable array won't be null at runtime, you can use the null-forgiving operator `!` to suppress nullable warnings. However, use this with caution to avoid runtime errors.
var arrayLength = length(myNullableArray!)
This treats `myNullableArray` as non-null, allowing you to access its `length` property without additional checks.
For complex scenarios, creating custom Bicep functions to handle nullable arrays can enhance code readability and maintainability.
@description('Ensures the array is not null')
function ensureArray(input: string[] | null) returns string[] {
return coalesce(input, ['default1', 'default2'])
}
var safeArray = ensureArray(myNullableArray)
This function `ensureArray` ensures that `safeArray` always contains a valid array.
Making arrays nullable in Azure Bicep is a powerful technique that enhances the flexibility and reusability of your infrastructure-as-code templates. By defining parameters with union types, handling null values gracefully, and implementing best practices, you can create robust and scalable Bicep configurations. Whether deploying simple resources or managing complex environments, understanding how to effectively manage nullable arrays ensures your deployments are both reliable and maintainable.