Bicep vs ARM JSON vs Terraform for Azure infrastructure as code
Verdict: For an Azure-only estate choose Bicep: readable, transpiles to ARM JSON, no author-managed state file. Preview any deployment with az deployment group what-if, which shows the create, modify and delete diff. Terraform only when you need multi-cloud.
| Criterion | Bicep | ARM JSON | Terraform |
|---|---|---|---|
| State | None; Azure stores all state | None; Azure stores all state | Author-managed remote state file |
| Language | Azure-native DSL, transpiles to ARM JSON at deploy | Verbose JSON with bracket function syntax | HCL, multi-cloud via providers |
| Modules | Publishable to a Bicep registry backed by an ACR | Nested (inline) and linked (URI) templates | Provider and registry modules |
| Change preview | az deployment group what-if shows the create/modify/delete diff | Same what-if applies to ARM deployments | terraform plan |
| Choose when | Azure-only estate wanting readable IaC without state files | Deployment scripts; per-resource apiVersion pinning | Multi-cloud across AWS, GCP and Azure |
Rules
- Bicep is the Azure-native DSL: the CLI transpiles it to ARM JSON at deploy time, Azure stores all state, and Resource Manager validates the result.
- Bicep modules can be published to a Bicep registry backed by an Azure Container Registry, so teams share reusable modules across pipelines.
- az deployment group what-if previews the resource and property create, modify and delete changes without applying anything.
- ARM deployment scripts embed PowerShell or Bash in a deployment; per-resource apiVersion pins the REST API version against breaking changes.
Traps
- validate checks template syntax and schema only; it does not show the resource-level create/modify/delete diff - use what-if for that.
- It is reversed in exam distractors: nested templates are inline in the parent, linked templates are referenced by URI.
- Terraform uses HCL and an author-managed state file; it is not Azure-native and does not transpile to ARM JSON.