5.1 ARM Templates, Bicep, and Deployment Workflow

Key Takeaways

  • ARM templates and Bicep describe desired Azure resource state and are deployed through Azure Resource Manager at subscription, resource group, management group, or tenant scope.
  • Bicep is the preferred authoring language for most administrator scenarios because it compiles to ARM JSON while remaining easier to read and modify.
  • Use what-if, validation, deployment names, parameters, outputs, and deployment history to predict and troubleshoot infrastructure changes.
  • Exported templates are useful for discovery, but exam scenarios usually expect you to simplify, parameterize, and redeploy rather than blindly reuse exported JSON.
Last updated: May 2026

Deployment Model

Azure Resource Manager is the control plane for most Azure resources. When you create a virtual machine in the portal, run az vm create, deploy a Bicep file, or submit an ARM template, the request is evaluated by ARM. ARM checks identity, RBAC, policy, resource provider registration, location availability, dependencies, quotas, and resource properties before the target resource provider creates or updates the resource.

For AZ-104, the important point is that templates are not a separate provisioning engine. They are a repeatable way to send the same desired-state request to ARM. You should be comfortable reading a template, finding the resource type, API version, location, name, properties, dependencies, parameters, and outputs. You should also be able to choose the right deployment scope.

ScopeCommon commandUse caseExam clue
Resource groupaz deployment group createVMs, NICs, disks, NSGs, public IPsMost compute deployments
Subscriptionaz deployment sub createResource groups, policy assignments, role assignmentsTemplate creates the resource group
Management groupaz deployment mg createGovernance across subscriptionsPolicy or initiative at hierarchy level
Tenantaz deployment tenant createTenant-level configurationRare administrator scenario

Bicep Versus ARM JSON

ARM templates are JSON documents. They are powerful, but complex expressions and nested objects can be hard to maintain. Bicep is a domain-specific language that compiles to ARM JSON. It uses symbolic names, cleaner parameters, modules, loops, and conditionals. You can decompile many ARM templates with az bicep decompile, but decompilation is a starting point, not guaranteed production-quality code.

A compact Bicep deployment for a VM support resource might look like this:

param location string = resourceGroup().location
param vnetName string = 'vnet-prod-compute'
param subnetName string = 'snet-vms'

resource vnet 'Microsoft.Network/virtualNetworks@2024-05-01' = {
  name: vnetName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.40.0.0/16'
      ]
    }
    subnets: [
      {
        name: subnetName
        properties: {
          addressPrefix: '10.40.1.0/24'
        }
      }
    ]
  }
}

output subnetId string = vnet.properties.subnets[0].id

The equivalent ARM template would contain the same resource provider type and properties but with JSON syntax, parameters, variables, and expression strings such as [resourceGroup().location]. In exam questions, Bicep answers often stand out because the symbolic resource name is used for dependency tracking. Explicit dependsOn is still possible, but Bicep usually infers dependencies when one resource references another.

Deployment Workflow

A practical workflow starts with a small, validated file. Use parameters for names, locations, VM sizes, admin usernames, environment labels, and settings that vary between dev, test, and production. Avoid hard-coding passwords. Use secure parameters, Key Vault references, managed identities, or deployment-time secrets handled by your pipeline.

Typical CLI workflow:

az login
az account set --subscription 00000000-0000-0000-0000-000000000000
az group create --name rg-prod-compute --location eastus
az deployment group what-if \
  --resource-group rg-prod-compute \
  --template-file main.bicep \
  --parameters vmName=vm-app-01 adminUsername=azureadmin
az deployment group create \
  --name vm-build-20260505 \
  --resource-group rg-prod-compute \
  --template-file main.bicep \
  --parameters @prod.parameters.json

Use what-if before changes that may replace, delete, or reconfigure resources. A deployment mode also matters. Incremental mode updates or creates resources defined in the template and leaves unrelated resources alone. Complete mode can delete resources not present in the template at the deployment scope. Complete mode is dangerous in shared resource groups and should not be selected casually in an exam scenario.

Parameters, Outputs, and Modules

A parameter file keeps environment values separate from reusable logic. Secure values should not be committed. Outputs are useful when later deployments need IDs, host names, or principal IDs. Modules let you split a design into network, VM, monitoring, and backup pieces.

param location string
param vmNames array

module vmModule './modules/windows-vm.bicep' = [for vmName in vmNames: {
  name: 'deploy-${vmName}'
  params: {
    location: location
    vmName: vmName
  }
}]

Loops are common for VM Scale Sets, diagnostic settings, role assignments, and repeated resource creation. The exam may ask you to identify a syntax issue, missing parameter, bad scope, or invalid dependency. Read the error and locate the layer: template parsing, ARM validation, Azure Policy denial, RBAC denial, provider registration, quota, or resource provider runtime error.

Export and Convert

The portal can export a template from a resource group or from deployment history. Export is useful for learning the property shape of a VM, disk, NIC, or scale set. It often includes generated names, defaults, read-only properties, and values you should parameterize or remove. For study purposes, compare the exported resource type with Microsoft Learn examples and current API versions.

Command examples:

az group export --name rg-prod-compute > exported.json
az bicep decompile --file exported.json
az bicep build --file main.bicep

A common troubleshooting scenario is a deployment that works in one subscription but fails in another. Check whether the destination subscription has the resource provider registered, the VM family quota available in the selected region, the same policy assignments, the same allowed locations, and permissions at the target scope. The same template can fail because the environment is different.

Troubleshooting Tree

SymptomFirst checkLikely fix
AuthorizationFailedRole assignment at deployment scopeAssign Contributor, VM Contributor plus network rights, or a custom role
InvalidTemplateSyntax, parameter name, function, scopeBuild Bicep locally and validate deployment
RequestDisallowedByPolicyPolicy assignment and exemptionChoose allowed SKU, tag, location, or request exemption
SkuNotAvailableRegion and VM sizePick a supported region or size
OperationNotAllowed quotaCompute usage and limitsRequest quota increase or choose another family
Resource provider errorActivity log and deployment operationsFix resource-specific properties

In the portal, use Resource group > Deployments > deployment name > Deployment details to inspect failed operations. In CLI, use az deployment operation group list --resource-group rg-prod-compute --name vm-build-20260505. The failed child operation usually contains more useful detail than the top-level deployment status.

Scenario Recognition

If a question asks for repeatable VM deployment across environments, choose Bicep or ARM templates. If it asks for one-time manual creation, the portal or CLI may be sufficient. If it asks to preview effects, choose what-if. If it asks to create resource groups and then VMs in one file, use subscription-scope deployment with modules or nested deployments. If it asks to simplify an exported template, remove read-only properties, parameterize environment differences, and keep only required resource definitions.

On the exam, do not assume Microsoft Learn access means you can research every syntax detail. Role-based exams can provide Learn access, but no extra exam time is added and access excludes Q&A, Practice Assessments, and profile. Know the deployment workflow well enough to answer from the scenario.

Test Your Knowledge

You need to deploy a resource group and then deploy several VMs into it from one repeatable template workflow. Which deployment scope should start the process?

A
B
C
D
Test Your Knowledge

A Bicep deployment fails with RequestDisallowedByPolicy. What should you check first?

A
B
C
D
Test Your Knowledge

Why should an exported ARM template usually be edited before reuse?

A
B
C
D