adaptive.run TECH BLOG

Cloud can be tricky sometimes. Find out what scenarios we've ran into that are worth being mentioned and explained.

Converting ARM Templates to Azure Bicep

Level: 200
Publishing date: 28-Feb-2025
Author: Catalin Popa


Introduction

This article explores the differences between Azure ARM templates and Azure Bicep, explaining their syntax variations and how to efficiently convert ARM templates into Bicep using Azure CLI.


What Are Azure ARM and Azure Bicep?

Both Azure ARM (Azure Resource Manager) and Bicep serve the same goal: defining and deploying infrastructure as code in Azure. However, before Azure Bicep was introduced, ARM templates—written in JSON—were the primary method for declarative infrastructure deployment. Due to JSON's rigid structure and verbosity, ARM templates can become complex, difficult to manage, and cumbersome to read.

Azure Bicep, on the other hand, is a domain-specific language (DSL) designed specifically for Azure infrastructure. It introduces a simplified syntax, improved readability, and enhanced reusability through modules. Despite its differences, Bicep is built on top of ARM, meaning every resource deployable via ARM can also be deployed with Bicep.

Mobirise
azure.microsoft.com

The diagram above illustrates the process of deploying a Bicep template through Azure Resource Manager. In this workflow, ARM templates act as an intermediate layer between Bicep and Azure Resource Manager. When a Bicep template is built, it is transpiled into an ARM JSON template, which is then processed by Azure for deployment.

By running:

az bicep build --file my-template.bicep

Bicep converts into an ARM template, ensuring compatibility with Azure’s deployment mechanisms. Similarly, existing ARM templates can be decompiled back into Bicep using:

az bicep decompile --file my-template.json

This transpilation process enables seamless interoperability between Bicep and ARM, making it easier to manage and optimize infrastructure as code. Transpiling refers to converting code from one language into another, preserving functionality while improving readability and maintainability.

Syntax Differences Between ARM and Bicep

1. Loops: Deploying Multiple Resources

Let’s compare an ARM template and its Bicep equivalent that deploys three Azure App Services instead of storage accounts.

ARM Template (JSON)

{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"variables": {
"appCount": 3,
"baseName": "[uniqueString(resourceGroup().id)]"
},
"resources": [
{
"name": "[concat(variables('baseName'), '-app-', copyIndex())]",
"type": "Microsoft.Web/sites",
"apiVersion": "2021-02-01",
"location": "[resourceGroup().location]",
"properties": {},
"copy": {
"name": "appLoop",
"count": "[variables('appCount')]"
      }
    }
  ]

Bicep Equivalent

var appCount = 3
var baseName = uniqueString(resourceGroup().id)

resource appService 'Microsoft.Web/sites@2021-02-01' = [for i in range(0, appCount): {
name: '${baseName}-app-${i}'
location: resourceGroup().location
properties: {}
}] 

✔ Bicep eliminates the JSON copy construct, replacing it with a for-loop.
✔ The syntax is cleaner, easier to read, and maintain.

2. Conditions: Conditionally Deploying a Resource

Let’s say we need to conditionally deploy a Log Analytics workspace based on a parameter.

ARM Template (JSON)

{
"parameters": {
"deployLogAnalytics": {
"type": "bool",
"defaultValue": true
  }
},
"resources": [
{
"condition": "[parameters('deployLogAnalytics')]",
"name": "log-analytics-workspace",
"type": "Microsoft.OperationalInsights/workspaces",
"apiVersion": "2021-06-01",
"location": "[resourceGroup().location]",
"properties": {}
    }
  ]

Bicep Equivalent

param deployLogAnalytics bool = true

resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-06-01' = if (deployLogAnalytics) {
name: 'log-analytics-workspace'
location: resourceGroup().location
properties: {}

✔ Bicep conditions are more intuitive, using if (...) before defining the resource.

3. Dependencies: Implicit vs. Explicit

Dependencies determine the order of deployment. Let’s deploy:

      • An Azure Key Vault
      • A Function App, which depends on Key Vault

        ARM Template (Explicit Dependency)

{
"resources": [
{
"name": "my-keyvault",
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2021-11-01",
"location": "[resourceGroup().location]",
"properties": {}
},
{
"name": "my-functionapp",
"type": "Microsoft.Web/sites",
"apiVersion": "2021-02-01",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', 'my-keyvault')]"
],
"properties": {}
    }
  ]

Bicep Equivalent (Implicit Dependency)

resource keyVault 'Microsoft.KeyVault/vaults@2021-11-01' = {
name: 'my-keyvault'
location: resourceGroup().location
properties: {}
}

resource functionApp 'Microsoft.Web/sites@2021-02-01' = {
name: 'my-functionapp'
location: resourceGroup().location
properties: {}

dependsOn: [keyVault] // Explicit dependency (not needed if keyVault is referenced)

✔ In Bicep, dependencies are inferred automatically.
✔ If a resource references another, Bicep automatically orders the deployment.
✔ dependsOn is only needed for complex deployments.

How to Convert an ARM Template to Bicep Using Azure CLI

Instead of rewriting ARM templates manually, use the Azure CLI to decompile JSON into Bicep.

Run the Following Command:

az bicep decompile --file template.json

🔹 This attempts to convert ARM to Bicep automatically.
🔹 Manual adjustments may still be needed.

Limitations of the ARM to Bicep Conversion

🚨 Automatic decompilation may not always be perfect. Some issues include:

✔ Explicit dependencies (dependsOn) may not be optimized.
✔ JSON expressions may be converted incorrectly.
✔ Loop structures (copy) may require manual adjustments.

To verify and refine the converted Bicep template, use:

az bicep build --file converted.bicep


Conclusion

🔹 Azure Bicep simplifies infrastructure deployments with cleaner syntax and modular support.
🔹 Bicep replaces ARM JSON templates, making code easier to read and maintain.
🔹 Implicit dependencies and intuitive loops reduce complexity in resource deployments.
🔹 Azure CLI can help migrate existing ARM templates to Bicep.

By transitioning to Azure Bicep, teams can reduce deployment errors, enhance maintainability, and accelerate infrastructure development in Azure. 🚀

Mobirise
adaptive.run

Transform your business.
Run adaptive.

Contact

Phone: +40 73 523 0005
Email: hello@adaptive.run

Mobirise Website Builder
Mobirise Website Builder

© Copyright  2019-2025 adaptive.run- All Rights Reserved