Quickstart: Create multiple resource instances in Bicep

Learn how to use different for syntaxes to create multiple resource instances in Bicep. Even though this article only shows creating multiple resource instances, the same methods can be used to define copies of module, variable, property, or output. To learn more, see Bicep loops.

This article contains the following topics:

Prerequisites

If you don't have an Azure subscription, create a free account before you begin.

To set up your environment for Bicep development, see Install Bicep tools. After completing those steps, you'll have Visual Studio Code and the Bicep extension. You also have either the latest Azure CLI or the latest Azure PowerShell module.

Create a single instance

In this section, you define a Bicep file for creating a storage account, and then deploy the Bicep file. The subsequent sections provide the Bicep samples for different for syntaxes. You can use the same deployment method to deploy and experiment those samples. If your deployment fails, it's likely one of the two causes:

  • The storage account name is too long. Storage account names must be between 3 and 24 characters in length and may contain numbers and lowercase letters only.
  • The storage account name isn't unique. Your storage account name must be unique within Azure.

The following Bicep file defines one storage account:

param rgLocation string = resourceGroup().location

resource createStorage 'Microsoft.Storage/storageAccounts@2023-04-01' = {
  name: 'storage${uniqueString(resourceGroup().id)}'
  location: rgLocation
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
}

Save the Bicep file locally, and then use Azure CLI or Azure PowerShell to deploy the Bicep file:

resourceGroupName = "{provide-a-resource-group-name}"
templateFile="{provide-the-path-to-the-bicep-file}"

az group create --name $resourceGroupName --location eastus

az deployment group create --resource-group $resourceGroupName --template-file $templateFile

Use integer index

A for loop with an index is used in the following sample to create two storage accounts:

param rgLocation string = resourceGroup().location
param storageCount int = 2

resource createStorages 'Microsoft.Storage/storageAccounts@2023-04-01' = [for i in range(0, storageCount): {
  name: '${i}storage${uniqueString(resourceGroup().id)}'
  location: rgLocation
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
}]

output names array = [for i in range(0,storageCount) : {
  name: createStorages[i].name
} ]

The index number is used as a part of the storage account name. After deploying the Bicep file, you get two storage accounts that are similar to:

Use integer index with 0 as the starting number

Inside range(), the first number is the starting number, and the second number is the number of times the loop will run. So if you change it to range(3,2), you'll also get two storage accounts:

Use integer index with 3 as the starting number

The output of the preceding sample shows how to reference the resources created in a loop. The output is similar to:

"outputs": {
  "names": {
    "type": "Array",
    "value": [
      {
        "name": "0storage52iyjssggmvue"
      },
      {
        "name": "1storage52iyjssggmvue"
      }
    ]
  }
},

Use array elements

You can loop through an array. The following sample shows an array of strings.

param rgLocation string = resourceGroup().location
param storageNames array = [
  'contoso'
  'fabrikam'
]

resource createStorages 'Microsoft.Storage/storageAccounts@2023-04-01' = [for name in storageNames: {
  name: '${name}str${uniqueString(resourceGroup().id)}'
  location: rgLocation
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
}]

The loop uses all the strings in the array as a part of the storage account names. In this case, it creates two storage accounts:

Use an array of strings

You can also loop through an array of objects. The loop not only customizes the storage account names, but also configures the SKUs.

param rgLocation string = resourceGroup().location
param storages array = [
  {
    name: 'contoso'
    skuName: 'Standard_LRS'
  }
  {
    name: 'fabrikam'
    skuName: 'Premium_LRS'
  }
]

resource createStorages 'Microsoft.Storage/storageAccounts@2023-04-01' = [for storage in storages: {
  name: '${storage.name}obj${uniqueString(resourceGroup().id)}'
  location: rgLocation
  sku: {
    name: storage.skuName
  }
  kind: 'StorageV2'
}]

The loop creates two storage accounts. The SKU of the storage account with the name starting with fabrikam is Premium_LRS.

Use an array of strings

Use array and index

In same cases, you might want to combine an array loop with an index loop. The following sample shows how to use the array and the index number for the naming convention.

param rgLocation string = resourceGroup().location
param storageNames array = [
  'contoso'
  'fabrikam'
]

resource createStorages 'Microsoft.Storage/storageAccounts@2023-04-01' = [for (name, i) in storageNames: {
  name: '${i}${name}${uniqueString(resourceGroup().id)}'
  location: rgLocation
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
}]

After deploying the preceding sample, you create two storage accounts that are similar to:

Use an array of strings and index number

Use dictionary object

To iterate over elements in a dictionary object, use the items function, which converts the object to an array. Use the value property to get properties on the objects.

param rgLocation string = resourceGroup().location

param storageConfig object = {
  storage1: {
    name: 'contoso'
    skuName: 'Standard_LRS'
  }
  storage2: {
    name: 'fabrikam'
    skuName: 'Premium_LRS'
  }
}

resource createStorages 'Microsoft.Storage/storageAccounts@2023-04-01' = [for config in items(storageConfig): {
  name: '${config.value.name}${uniqueString(resourceGroup().id)}'
  location: rgLocation
  sku: {
    name: config.value.skuName
  }
  kind: 'StorageV2'
}]

The loop creates two storage accounts. The SKU of the storage account with the name starting with fabrikam is Premium_LRS.

Use a dictionary object

Loop with condition

For resources and modules, you can add an if expression with the loop syntax to conditionally deploy the collection.

param rgLocation string = resourceGroup().location
param storageCount int = 2
param createNewStorage bool = true

resource createStorages 'Microsoft.Storage/storageAccounts@2023-04-01' = [for i in range(0, storageCount): if(createNewStorage) {
  name: '${i}storage${uniqueString(resourceGroup().id)}'
  location: rgLocation
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
}]

For more information, see conditional deployment in Bicep.

Clean up resources

When the Azure resources are no longer needed, use the Azure CLI or Azure PowerShell module to delete the quickstart resource group.

resourceGroupName = "{provide-the-resource-group-name}"

az group delete --name $resourceGroupName

Next steps