Introduction
Azure Resource Manager (ARM) remains Azure's native deployment engine in 2026. It lets you describe complete infrastructure as declarative JSON templates. This intermediate tutorial guides you through creating a working ARM template that includes parameters, variables, conditional resources, and outputs. You'll learn to deploy these templates via Azure CLI while avoiding common validation and dependency errors. Every section includes ready-to-use code.
Prerequisites
- Azure account with Contributor permissions
- Azure CLI 2.50+ installed
- Basic knowledge of JSON and Azure
- Code editor (VS Code recommended)
Create the Base Template
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"description": "Template ARM intermédiaire pour un compte de stockage"
},
"parameters": {},
"variables": {},
"resources": [],
"outputs": {}
}This file provides the minimum valid structure for an ARM template. The schema and content version are required for validation by Azure Resource Manager.
Add Parameters
{
"parameters": {
"storageAccountName": {
"type": "string",
"minLength": 3,
"maxLength": 24
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
}
}
}Parameters make the template reusable. The minLength/maxLength constraints prevent naming errors during deployment.
Define Variables and Resources
{
"variables": {
"storageAccountType": "Standard_LRS"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2023-01-01",
"name": "[parameters('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[variables('storageAccountType')]"
},
"kind": "StorageV2",
"properties": {}
}
]
}Variables centralize reusable values. The Storage Account resource uses the 2023-01-01 API, which remains valid in 2026.
Add Outputs
{
"outputs": {
"storageAccountId": {
"type": "string",
"value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
},
"primaryEndpoint": {
"type": "string",
"value": "[reference(parameters('storageAccountName')).primaryEndpoints.blob]"
}
}
}Outputs expose useful values after deployment (ID, endpoints). They are essential for chaining deployments.
Azure CLI Deployment Script
#!/bin/bash
RG_NAME="rg-arm-demo-2026"
LOCATION="westeurope"
STORAGE_NAME="starmdemo$(date +%s)"
az group create --name $RG_NAME --location $LOCATION
az deployment group create \
--resource-group $RG_NAME \
--template-file azuredeploy.json \
--parameters storageAccountName=$STORAGE_NAMEThis Bash script creates the resource group then deploys the template. The unique storage account name avoids conflicts.
Best Practices
- Always version your templates and use descriptive parameter names
- Prefer variables for calculated values instead of repeated expressions
- Add descriptions in parameter metadata
- Always test with What-If before deploying to production
- Use Bicep modules for complex projects while staying ARM-compatible
Common Errors to Avoid
- Forgetting the apiVersion property on resources (error 400)
- Using non-unique resource names without a random suffix
- Ignoring implicit dependencies between resources
- Failing to validate the template with az deployment group validate before running it
Going Further
Explore our advanced Azure IaC training and multi-environment deployment courses: https://learni-group.com/formations