How to Use Loops in Bicep to Create Multiple Resources
Creating ten storage accounts by hand, one by one, is slow and error-prone. With loops in Bicep you declare the resource once and Azure creates as many instances as you need from a list. This guide shows, step by step, how to use the for loop in Bicep to create multiple resources in a clean, reusable way.
Prerequisites
- An active Azure subscription.
- The Azure CLI installed, or the Cloud Shell inside the Azure portal.
- The Bicep extension in VS Code (optional, but it helps while writing).
- Basic Bicep knowledge: what parameters and resources are.
Step 1: Create the resource group
Every resource lives inside a resource group. We will create one just for this demo, so it is easy to delete everything at once later. Open a terminal and run:
az group create \
--name rg-bicep-loops \
--location westeurope
Keep the name rg-bicep-loops: this is where we will send the template.
Step 2: Build a loop over a list
Create a file called main.bicep. The core idea is simple: you declare an array with the data for each account and wrap the resource in [for ... : { ... }]. Bicep walks through the list and creates one account per item.
param location string = resourceGroup().location
param contas array = [
{
nome: 'vendas'
sku: 'Standard_LRS'
}
{
nome: 'compras'
sku: 'Standard_GRS'
}
]
resource storage 'Microsoft.Storage/storageAccounts@2023-01-01' = [for conta in contas: {
name: 'st${conta.nome}${uniqueString(resourceGroup().id)}'
location: location
sku: {
name: conta.sku
}
kind: 'StorageV2'
}]
Notice two details. The for conta in contas gives you, on each pass, the current object from the list, and you use its fields (conta.nome and conta.sku) to customize each resource. The uniqueString(resourceGroup().id) function generates a predictable suffix that helps keep the name globally unique, a requirement for storage accounts.
A storage account name only accepts lowercase letters and numbers and must be between 3 and 24 characters. Since uniqueString takes up 13 characters, keep your prefixes short so you do not exceed the limit.
Step 3: Use the index with range()
Sometimes you do not have a list of objects: you just want N identical copies. In that case, use the range() function to generate a sequence of numbers and grab the index on each pass. This is an alternative to Step 2:
param location string = resourceGroup().location
param numeroDeContas int = 3
resource storage 'Microsoft.Storage/storageAccounts@2023-01-01' = [for i in range(0, numeroDeContas): {
name: 'stdemo${i}${uniqueString(resourceGroup().id)}'
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
}]
The range(0, 3) produces the numbers 0, 1 and 2, so Bicep creates three accounts. Because the index i goes into the name, each account gets a different, valid name.
Step 4: Deploy and return the names
With the main.bicep file ready, send it to the resource group you created in Step 1:
az deployment group create \
--resource-group rg-bicep-loops \
--template-file main.bicep
Azure reads the loop, expands it into multiple resources, and creates all the accounts in a single operation. Going back to the Step 2 version (list of objects), you can also return the generated names by adding this output to the end of the file:
output nomesCriados array = [for i in range(0, length(contas)): storage[i].name]
Check the result
After the deployment finishes, confirm the accounts really exist. In the terminal, list the storage accounts in the resource group:
az storage account list \
--resource-group rg-bicep-loops \
--output table
You should see one row for each account the loop created. Alternatively, open the resource group in the Azure portal and confirm visually. To clean everything up at the end, delete the whole resource group with az group delete --name rg-bicep-loops.
Conclusion
With a single resource declaration and a for loop, you now create multiple resources from a list, without copying and pasting nearly identical blocks. From here, try combining the loop with a condition (if) to create resources only when it makes sense, or apply the same pattern to modules to scale entire architectures. What will be the first repetitive resource you turn into a loop?