adaptive.run TECH BLOG

Cloud can be tricky sometimes. Find out what scenarios we've ran into that are worth being mentioned and explained.

Understanding Nullability Operators in Azure Bicep

Level: 300
Publishing date: 17-Jan-2025
Author: Catalin Popa

When working with Azure Bicep, handling null values correctly is essential to prevent deployment failures and ensure templates behave as expected. While most developers are familiar with arithmetic (+, -) and comparison (==, !=) operators, Bicep also provides nullability operators that help manage null values effectively.

This article covers three key nullability operators in Azure Bicep:

      • Null-forgiving operator (!) – Suppresses null warnings during compilation.
      • Coalesce operator (??) – Returns the first non-null value in an expression.
      • Safe-dereference operator (.?) – Accesses object properties safely, preventing runtime                    errors.

Understanding these operators allows for better error handling, cleaner templates, and more resilient deployments.
_______________________________________________________________________________

Null-Forgiving Operator (!)

The null-forgiving operator (!) is used to suppress null warnings at compile time. It tells Bicep that a value will not be null, even if there's no explicit guarantee. If you're familiar with C#, it behaves similarly.

Why Use It?

In cases where Bicep expects a value but cannot verify its presence at compile time, using ! removes warnings while allowing the deployment to proceed. However, if the value is null at runtime, the deployment will fail.

Example: Selecting a Virtual Machine SKU

Consider a scenario where a virtual machine SKU is selected dynamically based on a price condition. The filter() function returns an array, and first() extracts the first item. Since first() might return null, Bicep throws a warning.

Bicep

var varVmSkus = [
{ name: 'Standard_DS3_v2' price: 200 }
{ name: 'Standard_B2s' price: 100 }
]

output outSelectedSku object = first(filter(varVmSkus, sku => sku.price < 150)) 

Problem:
• Bicep expects an object but might receive null, causing a warning.

Solution:
To suppress the warning, apply the null-forgiving operator (!):

Bicep

 output outSelectedSku object = first(filter(varVmSkus, sku => sku.price < 150))!

Now, Bicep assumes that first() will always return a valid object, allowing the deployment to proceed without warnings. However, if the condition does not match any SKU, the deployment will fail at runtime.
_______________________________________________________________________________

Coalesce Operator (??)

The coalesce operator (??) ensures that a non-null value is always used in an expression. If the left-side value is null, it falls back to the right-side value.
Mobirise
azure.microsoft.com

Why Use It?

      • Ensures that a valid fallback value is always available.
      • Avoids null-related warnings and errors.
      • Can be chained to check multiple values.

Example: Assigning a Default Network Security Group Name

Consider a scenario where a Network Security Group (NSG) name is either provided by the user or assigned a default value if missing.

Bicep

param parNsgName string?

resource resNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = {
name: parNsgName ?? 'default-nsg'
location: resourceGroup().location

How It Works:

     • If parNsgName is provided, it is used as the NSG name.
     • If parNsgName is null, "default-nsg" is assigned instead.

Coalescing Multiple Values

Bicep allows chaining multiple values with ??. The first non-null value is selected:

Bicep

param parNsgName string?
var varBackupName = 'backup-nsg'

resource resNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = {
name: parNsgName ?? varBackupName ?? 'final-default-nsg'

In this case:

      1. If parNsgName is set, it is used.
      2. If parNsgName is null, varBackupName is checked.
      3. If both are null, "final-default-nsg" is used as a last fallback.

Using ?? helps prevent null-related runtime errors, ensuring a valid value is always assigned.
_______________________________________________________________________________

Safe-Dereference Operator (.?)

The safe-dereference operator (.?) allows you to safely access properties of objects or arrays without causing runtime failures when properties are missing.

Why Use It?

Without .?, trying to access a missing property results in a deployment failure. The safe-dereference operator prevents this by returning null instead of throwing an error.

Example: Configuring a Public IP for a Virtual Machine

Imagine a scenario where an Azure Virtual Machine (VM) might be deployed with or without a Public IP address. The Bicep template dynamically assigns a value based on availability.

Without Safe-Dereference (.?) – Risk of Deployment Failure

Bicep

param parVmPublicIp object?

resource resVirtualMachine 'Microsoft.Compute/virtualMachines@2023-07-01' = {
name: 'example-vm'
location: resourceGroup().location
properties: {
networkProfile: {
networkInterfaces: [
{
id: parVmPublicIp.id
        }
      ]
    }
  }

If parVmPublicIp is null (i.e., the VM has no public IP), referencing .id will cause a deployment failure.

Using Safe-Dereference (.?) – Prevents Deployment Errors

Bicep

resource resVirtualMachine 'Microsoft.Compute/virtualMachines@2023-07-01' = {
name: 'example-vm'
location: resourceGroup().location
properties: {
networkProfile: {
networkInterfaces: [
{
id: parVmPublicIp.?id
        }
      ]
    }
  }

Now, if parVmPublicIp is null, .id will not be accessed, and the deployment will not fail.

Alternative Approach: Using contains()

Before .? was introduced, the same behavior was achieved using contains():

id: contains(parVmPublicIp, 'id') ? parVmPublicIp.id : null

While this works, .? is cleaner and more readable, making it the recommended approach.
_______________________________________________________________________________

Conclusion

Handling null values in Azure Bicep correctly ensures reliable deployments and prevents runtime errors.

Recap of Nullability Operators:

Null-forgiving (!) – Suppresses compile-time warnings when a value is assumed to be non-null.
Coalesce (??) – Ensures a non-null value is assigned, falling back to a default if needed.
Safe-dereference (.?) – Prevents runtime failures when accessing potentially missing properties.

By mastering these operators, you can write cleaner, more resilient Bicep templates that adapt to different deployment scenarios without errors.


Mobirise
adaptive.run

Transform your business.
Run adaptive.

Contact

Phone: +40 73 523 0005
Email: hello@adaptive.run

Mobirise Website Builder
Mobirise Website Builder

© Copyright  2019-2025 adaptive.run- All Rights Reserved