Feature Matrix: Language & Governance

  ARM Templates Bicep Terraform (azurerm) Terraform (azapi)
Language JSON Bicep DSL HCL HCL
Maintained by Microsoft Microsoft HashiCorp / OpenTofu Microsoft
License Free Free / MIT BSL (Terraform) / MPL (OpenTofu) MPL 2.0
Azure-native Yes Yes Yes (via azurerm provider) Yes (via azapi provider)
Multi-cloud No No Yes Azure only
State file No No Yes Yes

Feature Matrix: Day-0 & Syntax

  ARM Templates Bicep Terraform (azurerm) Terraform (azapi)
Day-0 coverage Full Full Provider lag possible Full — mirrors ARM/Bicep API
Field names ARM API names ARM API names Custom HCL-friendly names ARM API names (Bicep-aligned)
Plan preview --what-if --what-if terraform plan terraform plan
Loops copy element for expression for_each / count for_each / count
Conditions condition element if expression count = cond ? 1 : 0 count = cond ? 1 : 0

Feature Matrix: Tooling & Ecosystem

  ARM Templates Bicep Terraform (azurerm) Terraform (azapi)
Modules / reuse Linked templates Modules + Registry Modules + Registry Modules + Registry
IDE support Good Excellent Excellent Good
Learning curve Steep Moderate Moderate Low for Bicep users
Community Large Medium (growing) Very large Small (growing)

Plan vs What-If

Both terraform plan and --what-if preview changes before applying, but they work differently:

  terraform plan az deployment ... --what-if
Diff source State file + live refresh Azure Resource Manager
Accuracy High Moderate — known noisy diffs
Saveable output Yes (-out=tfplan) No
Apply from saved plan Yes (terraform apply tfplan) No
Cross-resource impacts Shown via dependency graph Not shown

See also: Bicep · Terraform

Same Resource, Four Ways

Deploy a Storage Account (Standard LRS, StorageV2) in each tool — flip through the next four slides to compare them directly.

ARM Template (~20 lines)

{
  "type": "Microsoft.Storage/storageAccounts",
  "apiVersion": "2023-01-01",
  "name": "[parameters('storageAccountName')]",
  "location": "[parameters('location')]",
  "sku": { "name": "Standard_LRS" },
  "kind": "StorageV2",
  "properties": {
    "minimumTlsVersion": "TLS1_2",
    "allowBlobPublicAccess": false,
    "supportsHttpsTrafficOnly": true
  }
}

Bicep (~10 lines)

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: storageAccountName
  location: location
  sku: { name: 'Standard_LRS' }
  kind: 'StorageV2'
  properties: {
    minimumTlsVersion: 'TLS1_2'
    allowBlobPublicAccess: false
    supportsHttpsTrafficOnly: true
  }
}

Terraform / azurerm (~9 lines)

resource "azurerm_storage_account" "main" {
  name                             = var.storage_account_name
  resource_group_name              = var.resource_group_name
  location                         = var.location
  account_tier                     = "Standard"
  account_replication_type         = "LRS"
  account_kind                     = "StorageV2"
  min_tls_version                  = "TLS1_2"
  allow_nested_items_to_be_public  = false
  https_traffic_only_enabled       = true
}

Terraform / azapi (~12 lines)

resource "azapi_resource" "storage" {
  type      = "Microsoft.Storage/storageAccounts@2023-01-01"
  name      = var.storage_account_name
  location  = var.location
  parent_id = var.resource_group_id

  body = {
    sku  = { name = "Standard_LRS" }
    kind = "StorageV2"
    properties = {
      minimumTlsVersion        = "TLS1_2"
      allowBlobPublicAccess    = false
      supportsHttpsTrafficOnly = true
    }
  }
}

Field Names, Side by Side

Field names mirror the Bicep/ARM API exactly in ARM, Bicep, and azapi — minimumTlsVersion instead of min_tls_version, allowBlobPublicAccess instead of allow_nested_items_to_be_public. Only azurerm renames fields to its own convention. See the azapi module for more.

Support for New Resources

New Azure features appear in ARM and Bicep on day 0 — the moment Microsoft ships a feature, the ARM API supports it. Terraform’s azurerm provider typically follows within days to weeks, depending on maintainer availability. The azapi provider (maintained by Microsoft) closes this gap entirely by calling the ARM REST API directly.

Support for Many Providers

Only Terraform / OpenTofu supports managing resources outside of Azure in the same workflow. Popular non-Azure providers include aws, google, kubernetes, helm, vault, datadog, and hundreds more.


There’s no lab for this module — it’s a synthesis of the previous five, not a new tool with its own syntax to practice. The quiz below pulls from the comparison table instead.

📝 Quiz — Comparison

Next Up

The Capstone puts all four side by side on one task, with a final mixed quiz.