Getting Started with Bicep Loops and Conditions: Implementing Dynamic Deployments

When it comes to managing cloud infrastructure, two things are non-negotiable: scalability and flexibility. You want your deployment templates to be adaptable, reusable, and easy to maintain. That’s where Bicep comes into play. As a Domain-Specific Language (DSL) for Azure Resource Manager (ARM) templates, Bicep makes managing Azure resources simpler. One of its standout features is the ability to implement loops and conditions, which help make your templates more dynamic and suited for various deployment scenarios.

In this post, we’ll take a closer look at how you can leverage loops and conditions in Bicep to streamline and customize your Azure deployments effectively.

Why Use Loops and Conditions in Bicep?

Manually defining multiple resources or varying configurations can be time-consuming and error-prone. With Bicep’s loops and conditions, you can automate repetitive tasks and embed logic into your deployments, making it easier to:

  • Deploy multiple instances of a resource.
  • Configure resources based on specific inputs or conditions.
  • Reuse templates across different environments (like dev, staging, or production) with minimal changes.

Let’s dive into how loops and conditions work in Bicep.

Loops in Bicep

Loops in Bicep enable you to deploy multiple instances of a resource or repeatedly apply the same logic. The most common loop is the for loop, which you can use to iterate over arrays or ranges.

Example 1: Deploying Multiple Storage Accounts with a For Loop

Imagine you need to deploy several storage accounts. Instead of defining each one manually, you can use a loop to simplify the process:

param storageAccountNames array = [
  'storageAccount1'
  'storageAccount2'
  'storageAccount3'
]

resource storageAccounts 'Microsoft.Storage/storageAccounts@2023-05-01' = [for name in storageAccountNames: {
  name: name
  location: 'EastUS'
  kind: 'StorageV2'
  sku: {
    name: 'Standard_LRS'
  }
}]

In this example:

  • The parameter storageAccountNames is defined as an array of names.
  • The for loop iterates over each name in the array and creates a storage account for each, reducing the amount of code you need to write and manage.

Example 2: Creating Resources Dynamically Based on Count

Another common scenario is deploying resources based on a dynamic count, such as creating multiple VMs based on user input.

param vmCount int = 3

resource vms 'Microsoft.Compute/virtualMachines@2024-07-01' = [for i in range(0, vmCount): {
  name: 'myVM-${i}'
  location: 'EastUS'
  properties: {
    hardwareProfile: {
      vmSize: 'Standard_DS1_v2'
    }
  }
}]

Here:

  • The vmCount parameter specifies how many VMs to deploy.
  • The range(0, vmCount) function generates a sequence from 0 to vmCount - 1, which is used by the loop to deploy that number of VMs.

Conditions in Bicep

Conditions let you control whether or not a resource is deployed based on a boolean expression. This is useful for scenarios where you only want certain resources to be created in specific environments (like production vs. development).

Example 1: Conditional Resource Deployment

Let’s say you only want to deploy a firewall if the environment is set to “production.”

param environment string = 'dev'

resource firewall 'Microsoft.Network/azureFirewalls@2023-11-01' = if (environment == 'prod') {
  name: 'prodFirewall'
  location: 'EastUS'
  properties: {
    sku: {
      name: 'AZFW_VNet'
    }
  }
}

In this case:

  • The firewall will only be deployed if the environment parameter equals ‘prod’. If the condition isn’t met, the deployment of the firewall is skipped.

Example 2: Using Conditions with Output

You can also use conditions when defining outputs.

param deployDatabase bool = true

resource sqlDatabase 'Microsoft.Sql/servers/databases@2023-05-01-preview' = if (deployDatabase) {
  name: 'myDatabase'
  location: 'EastUS'
  properties: {
    collation: 'SQL_Latin1_General_CP1_CI_AS'
  }
}

output databaseName string = sqlDatabase.name

Here:

  • The SQL database will only be deployed if deployDatabase is true. If the condition is false, no database is deployed, and the output won’t return a value.

Combining Loops and Conditions

For even more flexibility, you can combine loops and conditions in Bicep. This allows you to deploy multiple resources conditionally based on user input.

Example: Conditional Deployment with Loop

param deployResources bool = true
param resourceNames array = [
  'resource1'
  'resource2'
  'resource3'
]

resource resources 'Microsoft.Resources/deployments@2024-03-01' = [for name in resourceNames: if (deployResources) {
  name: '${name}-deployment'
  properties: {
    mode: 'Incremental'
  }
}]

In this example:

  • If deployResources is true, the loop will iterate over the resourceNames array and deploy each resource.
  • If false, no resources will be deployed.

This approach allows you to easily control the deployment of entire sets of resources with minimal effort.

Conclusion

By utilizing loops and conditions in Bicep, you can create cleaner, more efficient, and flexible infrastructure code. This approach helps you:

  • Eliminate redundancy by looping through resource definitions.
  • Deploy resources conditionally based on parameters.
  • Simplify infrastructure management across different environments and scenarios.

Start incorporating these powerful features into your Bicep templates today and watch your Azure deployments become more dynamic and manageable.