ARM Templates & Bicep: Infrastructure as Code
Azure Resource Manager templates and Bicep files let you define infrastructure in code β deploy the same environment every time, no clicking required. Learn to read, modify, and deploy them like an Azure admin pro.
What is Infrastructure as Code?
Infrastructure as Code is like a recipe for your Azure environment.
Instead of clicking through the Azure portal to create a VM, a storage account, and a network, you write it all down in a file. Then you run the file and Azure creates everything automatically. Need the same setup in another region? Run the same file. Need to recreate after a disaster? Run the same file.
Azure supports two languages for this: ARM templates (JSON β verbose but powerful) and Bicep (cleaner syntax, compiles to ARM). Both do the same job; Bicep is just easier to read and write.
ARM template structure
Every ARM template has this structure:
// ARM Template (JSON)
// "$schema": defines the template version
// "contentVersion": your versioning
// "parameters": inputs (like VM name, size)
// "variables": computed values
// "resources": what to create
// "outputs": values returned after deployment
The sections you must know:
| Section | Purpose | Required? |
|---|---|---|
| $schema | Template format version | Yes |
| contentVersion | Your template version (e.g., β1.0.0.0β) | Yes |
| parameters | User inputs at deploy time (VM name, size, location) | No |
| variables | Computed values used in the template | No |
| resources | The Azure resources to create | Yes |
| outputs | Values returned after deployment (like IP addresses) | No |
Bicep β the cleaner alternative
Bicep does the same thing as ARM JSON but with much cleaner syntax:
| ARM Template Feature | ARM JSON | Bicep |
|---|---|---|
| Parameter | βparametersβ section with type definitions | param vmName string |
| Variable | βvariablesβ section | var subnetId = ... |
| Resource | Nested JSON object in βresourcesβ array | resource vm 'Microsoft.Compute/virtualMachines@2023-03-01' |
| Reference another resource | [resourceId(...)] function | storageAccount.id (direct reference) |
| String concatenation | [concat('vm-', parameters('name'))] | String interpolation: 'vm-$dollarleftbracename}' |
| Feature | ARM Template (JSON) | Bicep |
|---|---|---|
| Language | JSON β verbose, curly braces everywhere | Domain-specific β clean, concise syntax |
| Learning curve | Steep β deeply nested JSON | Gentle β reads almost like pseudocode |
| Tooling | VS Code extension, Azure portal | VS Code extension with intellisense, linting, formatting |
| Module support | Linked/nested templates (complex) | Native modules (simple imports) |
| Deployment engine | Azure Resource Manager | Compiles to ARM JSON β same engine |
| Which to learn? | Read existing templates | Write new infrastructure |
Exam tip: You need to READ templates, not write from scratch
The exam tests whether you can interpret and modify templates β not write them from memory. Youβll see a template snippet and be asked: βWhat does this deploy?β or βWhat parameter needs to change to use a different VM size?β
Focus on understanding the structure: find the resource type, find the parameters, understand what values are being used.
Deploying templates
Four ways to deploy ARM/Bicep templates:
| Method | Command |
|---|---|
| Azure CLI | az deployment group create --resource-group myRG --template-file main.bicep |
| PowerShell | New-AzResourceGroupDeployment -ResourceGroupName myRG -TemplateFile main.bicep |
| Azure Portal | Upload template in βDeploy a custom templateβ |
| Cloud Shell | Same CLI/PowerShell commands in the browser |
Deployment modes:
- Incremental (default) β adds resources defined in the template; leaves existing resources untouched
- Complete β adds resources AND deletes any resources in the resource group that arenβt in the template
Exam tip: Complete mode is dangerous
Complete mode deletes resources not in the template. If you deploy a template with only a VM in Complete mode to a resource group that has a VM and a database, the database gets deleted. The exam tests whether you understand this distinction. Default is Incremental (safe). Always specify explicitly.
Exporting and converting
Export an existing deployment as ARM template:
- Azure Portal β Resource Group β Deployments β select deployment β Download template
- Azure Portal β Resource β Export template (sidebar)
- CLI:
az group export --name myResourceGroup
Convert ARM JSON to Bicep:
az bicep decompile --file template.json
Convert Bicep to ARM JSON:
az bicep build --file main.bicep
Knowledge check
Alex deploys an ARM template in Complete mode to a resource group that contains a VM, a storage account, and a SQL database. The template only defines the VM. What happens to the storage account and SQL database?
A Bicep file contains: param location string = 'uksouth'. What does this line define?
π¬ Video coming soon