ARM Templates
Introduction
Section titled “Introduction”Azure Resource Manager (ARM) is the deployment and management layer for Azure. Every request to manage a resource, whether it comes from the Azure portal, the Azure CLI, an SDK, Terraform, or Bicep, reaches Resource Manager as an ARM operation. Requests that use a resource, such as uploading a blob or reading a secret, go to the service’s own data-plane endpoint instead. Declarative deployments reach it as ARM templates, JSON files that define the resources to deploy.
LocalStack for Azure implements the Resource Manager control plane, which is what lets infrastructure-as-code tools work against the emulator.
ARM templates need no extra configuration: once lstk az start-interception redirects the Azure CLI to the emulator, az deployment group create deploys templates to the emulator.
Getting started
Section titled “Getting started”This guide shows you how to deploy a storage account with an ARM template, pass the parameters from a file, and inspect the deployment.
Prerequisites
Section titled “Prerequisites”- The Azure CLI.
- LocalStack for Azure and the
lstkCLI, with the emulator running. For more information, see Installation.
Redirect the az commands to the emulator:
lstk az start-interceptionThis command changes your global Azure CLI configuration to use the LocalStack cloud until you run lstk az stop-interception.
For more information, see Azure CLI.
Write a template
Section titled “Write a template”Create a template that declares a storage account and returns its resource ID as an output:
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "storageAccountName": { "type": "string", "metadata": { "description": "Globally unique storage account name." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]" } }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2023-01-01", "name": "[parameters('storageAccountName')]", "location": "[parameters('location')]", "sku": { "name": "Standard_LRS" }, "kind": "StorageV2" } ], "outputs": { "storageId": { "type": "string", "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" } }}Deploy the template
Section titled “Deploy the template”Create a resource group, and deploy the template to it:
az group create --name MyResourceGroup --location westeurope
az deployment group create \ --resource-group MyResourceGroup \ --name my-arm-deployment \ --template-file azuredeploy.json \ --parameters storageAccountName=lsdocsarm001 \ --query "{state:properties.provisioningState, outputs:properties.outputs}"The --query argument reduces the deployment to its provisioning state and the template outputs:
{ "outputs": { "storageId": { "type": "String", "value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MyResourceGroup/providers/Microsoft.Storage/storageAccounts/lsdocsarm001" } }, "state": "Succeeded"}The emulator evaluates template functions, such as resourceGroup(), parameters(), and resourceId(), and template outputs as Azure does.
Use a parameter file
Section titled “Use a parameter file”To keep the parameter values out of the command line, store them in a parameter file:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "storageAccountName": { "value": "lsdocsarm001" } }}Pass the file to the deployment with the @ prefix:
az deployment group create \ --resource-group MyResourceGroup \ --name my-arm-deployment \ --template-file azuredeploy.json \ --parameters @azuredeploy.parameters.json \ --query properties.provisioningState"Succeeded"Inspect the deployment
Section titled “Inspect the deployment”List the deployments of the resource group:
az deployment group list --resource-group MyResourceGroup --output tableName State Timestamp Mode ResourceGroup----------------- --------- -------------------------------- ----------- ---------------my-arm-deployment Succeeded 2026-10-12T09:39:26.179179+00:00 Incremental MyResourceGroupTo see the complete deployment, including its parameters, its outputs, and the resources that it created, run az deployment group show --resource-group MyResourceGroup --name my-arm-deployment.
Resource Manager records an operation for each resource of a deployment. When a deployment fails, list its operations to see which resource failed and why:
az deployment operation group list \ --resource-group MyResourceGroup --name my-arm-deployment \ --query "[].{resource:properties.targetResource.resourceType, \ state:properties.provisioningState, \ message:properties.statusMessage.error.message}" -o tableClean up
Section titled “Clean up”Delete the resource group and the resources that it contains:
az group delete --name MyResourceGroup --yesTo make the az commands target Azure again, stop the interception:
lstk az stop-interceptionConvert between Bicep and ARM JSON
Section titled “Convert between Bicep and ARM JSON”To debug a Bicep deployment, compile the Bicep file to the ARM JSON that the Azure CLI submits to Resource Manager:
az bicep build --file main.bicep --stdoutThe metadata._generator block of the emitted template records the Bicep version and a hash of the template.
To migrate an existing ARM template to Bicep, decompile it:
az bicep decompile --file azuredeploy.jsonThe command writes azuredeploy.bicep next to the template.
Decompilation is a best-effort conversion, so review the generated file before you use it.
Deployment modes
Section titled “Deployment modes”az deployment group create uses Incremental mode by default, which leaves the resources that the template doesn’t declare untouched.
On Azure, Complete mode, which you select with --mode Complete, deletes those resources.
Limitations
Section titled “Limitations”- The emulator supports deployments to a resource group (
az deployment group create) and to a subscription (az deployment sub create), but not to a management group or a tenant. az deployment group validatereturns an empty result without validating the template, so it doesn’t catch the errors that Azure reports during validation.az deployment group what-ifisn’t supported: the emulator doesn’t implement the What-If operation, so the command fails.
For the other limitations of the Resource Manager emulator, see Resource Manager.