Introduction
Bicep is the Domain-Specific Language (DSL) developed by Microsoft to simplify Azure Resource Manager (ARM) templates. Unlike verbose ARM JSON, Bicep offers concise, readable, type-safe syntax, making Infrastructure as Code (IaC) accessible even for beginners. In 2026, Bicep is the standard tool for Azure deployments, used by millions of DevOps developers.
Why adopt it? It reduces syntax errors, supports reusable modules, native loops, and conditions. Imagine deploying a storage account, App Service, and database in a single readable file instead of nested JSON. This beginner tutorial guides you from zero: installation, first template, parameters, variables, outputs, and deployment. By the end, you'll master the basics to scale to complex environments. Ready to turn manual deployments into idempotent code? (142 words)
Prerequisites
- A free Azure account (create one at portal.azure.com)
- Azure CLI installed (version 2.30+)
- Code editor like VS Code with the Bicep extension
- Basic command-line knowledge
Install Bicep and Log in to Azure
az login
az extension add --name bicep --yes
az bicep version
az group create --name rg-bicep-demo --location francecentralThese commands log you into Azure, install the official Bicep extension, and create a resource group rg-bicep-demo in France Central. Verify the installation with az bicep version. Pitfall: Without az login, deployments fail with an authentication error.
Your First Bicep Template: A Storage Account
Let's start with a simple template: deploy an Azure storage account. Bicep uses TypeScript-like syntax with resource, param, var, and output. Copy the following code into main.bicep.
Create the Simple main.bicep File
@description('Compte de stockage pour le demo Bicep')
param storageAccountName string = 'stbicep${uniqueString(resourceGroup().id)}'
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = {
name: storageAccountName
location: resourceGroup().location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
}This template declares a parameter for the unique storage account name (avoids collisions) and creates a StorageV2 account with Standard_LRS SKU. uniqueString() generates a hashed suffix based on the RG. Pitfall: Non-unique names cause deployment errors; always use uniqueString() for global resources.
Deploy Your First Template
az deployment group create --resource-group rg-bicep-demo --template-file main.bicepDeploys the template to the created RG. Bicep automatically compiles to ARM JSON in the background. Check it in the Azure portal. Pitfall: If the .bicep file has errors, use az bicep build --file main.bicep to debug the generated JSON.
Adding Parameters and a JSON File
For more flexibility, externalize parameters into a JSON file. This enables reusable deployments without modifying the Bicep file.
Template with Required Parameters
@description('Compte de stockage paramétré')
@minLength(3)
@maxLength(24)
param storageAccountName string
@description('Emplacement')
@allowed([
'francecentral'
'northeurope'
])
param location string = 'francecentral'
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = {
name: storageAccountName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
}
output storageAccountId string = storageAccount.id
output storageAccountName string = storageAccount.nameAdds decorators like @minLength and @allowed to validate inputs at compile time. Outputs expose the ID and name for chaining. Pitfall: Without validation, invalid params crash runtime deployment; Bicep catches them early.
Parameters File params.json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountName": {
"value": "stbicepdemo123"
},
"location": {
"value": "francecentral"
}
}
}This JSON provides concrete values. The schema enables VS Code autocompletion. Pitfall: A value not matching @allowed triggers a Bicep validation error before deployment.
Deploy with Parameters
az deployment group create --resource-group rg-bicep-demo --template-file main-params.bicep --parameters @params.jsonUses --parameters @params.json to inject values. Outputs display in the console. Pitfall: Forgetting @ treats the file as a string; always use @file for JSON.
Variables, Conditions, and Loops
Level up: Use var for computations, if for conditionals, and for for arrays. Example: Deploy 2 containers if needed.
Advanced Template with var, if, and for
param storageAccountName string
param location string = 'francecentral'
param enableContainers bool = true
param containerNames array = [
'data'
'logs'
]
var tags = {
'project': 'bicep-demo'
'env': 'dev'
}
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = {
name: storageAccountName
location: location
tags: tags
sku: { name: 'Standard_LRS' }
kind: 'StorageV2'
}
resource container 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-05-01' = [for name in containerNames: {
name: '${name}'
properties: {
publicAccess: 'None'
}
dependsOn: [
storageAccount
]
if: enableContainers
}]var tags centralizes metadata. The for loop creates containers dynamically. if: enableContainers makes it conditional. dependsOn manages order. Pitfall: Without dependsOn, creation order is unpredictable; Bicep often infers it, but be explicit for safety.
Advanced Deployment and Cleanup
az deployment group create --resource-group rg-bicep-demo --template-file main-advanced.bicep --parameters storageAccountName=stbicepadv123 location=francecentral enableContainers=true containerNames='["data","logs"]'
# Nettoyage
az group delete --name rg-bicep-demo --yes --no-waitPasses params inline for quick testing. Cleanup deletes everything. Pitfall: CLI array params require JSON strings; use a file for complexity.
Best Practices
- Modularize: Break into reusable
.bicepmodules withmodulefor DRY principles. - Always validate: Use decorators like
@secureand@minValuefor safe inputs. - Use targets: Set
targetScope = 'subscription'for multi-RG deployments. - Integrate CI/CD: GitHub Actions or Azure DevOps with
az bicep build. - Version APIs: Pin like
@2023-05-01for stability.
Common Errors to Avoid
- Non-unique names: Forgetting
uniqueString()for global storage/App Services. - Wrong scope: Deploying at resource group level without
targetScope = 'resourceGroup'. - Unsecured params: Passing secrets in plain text; use
@secure()and Key Vault. - Ignoring dependsOn: Wrong creation order leads to timeouts.
Next Steps
Master modules, advanced loops, and existing resources. Check the official Bicep docs, Bicep playground. For pro expertise, explore our Learni DevOps Azure trainings.