Skip to content
Get Started for Free

ARM Templates

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.

This guide shows you how to deploy a storage account with an ARM template, pass the parameters from a file, and inspect the deployment.

  • The Azure CLI.
  • LocalStack for Azure and the lstk CLI, with the emulator running. For more information, see Installation.

Redirect the az commands to the emulator:

Terminal window
lstk az start-interception

This 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.

Create a template that declares a storage account and returns its resource ID as an output:

azuredeploy.json
{
"$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'))]"
}
}
}

Create a resource group, and deploy the template to it:

Terminal window
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:

Output
{
"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.

To keep the parameter values out of the command line, store them in a parameter file:

azuredeploy.parameters.json
{
"$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:

Terminal window
az deployment group create \
--resource-group MyResourceGroup \
--name my-arm-deployment \
--template-file azuredeploy.json \
--parameters @azuredeploy.parameters.json \
--query properties.provisioningState
Output
"Succeeded"

List the deployments of the resource group:

Terminal window
az deployment group list --resource-group MyResourceGroup --output table
Output
Name State Timestamp Mode ResourceGroup
----------------- --------- -------------------------------- ----------- ---------------
my-arm-deployment Succeeded 2026-10-12T09:39:26.179179+00:00 Incremental MyResourceGroup

To 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:

Terminal window
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 table

Delete the resource group and the resources that it contains:

Terminal window
az group delete --name MyResourceGroup --yes

To make the az commands target Azure again, stop the interception:

Terminal window
lstk az stop-interception

To debug a Bicep deployment, compile the Bicep file to the ARM JSON that the Azure CLI submits to Resource Manager:

Terminal window
az bicep build --file main.bicep --stdout

The 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:

Terminal window
az bicep decompile --file azuredeploy.json

The command writes azuredeploy.bicep next to the template. Decompilation is a best-effort conversion, so review the generated file before you use it.

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.

  • 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 validate returns an empty result without validating the template, so it doesn’t catch the errors that Azure reports during validation.
  • az deployment group what-if isn’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.

Was this page helpful?