Updated 6 September 2026: deployment stacks, AVM's Terraform expansion, the native terraform test framework, azurerm 4.x, and a full decision matrix.
Two years ago the Bicep-vs-Terraform conversation was easier: Terraform won on ecosystem, Bicep on Azure-native ergonomics. In 2026 the picture is more nuanced. Bicep closed most of the tooling gap, Terraform's licensing story is stable, and the OpenTofu fork has given Terraform users more options. This is an honest comparison aimed at teams making the choice for a new Azure workload, or reconsidering an existing one.
Already leaning Bicep? Our follow-up covers the practical move: Migrating from Terraform to Bicep on Azure, including state handling, coexistence patterns and CI/CD changes.
Summary
- Azure-only, small-to-mid team, no multi-cloud ambition. Bicep is simpler, cheaper to operate, and ergonomically tight with Azure.
- Multi-cloud or heavy third-party integration. Terraform (or OpenTofu) keeps paying for itself through the ecosystem.
- Large platform team with existing Terraform investment. The migration cost is rarely worth it.
What Changed Since 2024
Four developments moved the needle, and any comparison that skips them is describing 2023.
- Deployment stacks went GA. Bicep finally has an answer to "how do I delete everything this template created", historically its weakest point against Terraform's
destroy. More below. - Azure Verified Modules grew up, in both languages. AVM is often described as a Bicep story. It is not: Microsoft publishes verified modules for Terraform too, which quietly removed one of Bicep's talking points.
- Terraform shipped a native test framework. Since 1.6,
terraform testruns HCL-defined tests without the Go toolchain that Terratest demanded. Testing stopped being an argument for staying away. - The azurerm 4.x provider line cleaned house. Resource provider registration became controllable, behavior got more consistent, and some of the naming legacy was retired. The provider-lag complaint is smaller than it was, though not gone.
OpenTofu, meanwhile, settled from fork drama into a boring, stable option under the Linux Foundation, and added client-side state encryption, which Terraform itself still lacks natively. Boring is a compliment in infrastructure tooling.
State Management
Still the single biggest operational difference, so it deserves the most space. Terraform keeps an explicit state file, and everything good and bad about Terraform flows from that decision. The good: plan can diff desired against recorded state without touching the cloud, targeted operations and moved blocks let you refactor safely, and destroy knows exactly what it owns. The bad is operational. On Azure the standard backend is a storage account with blob-lease locking, which means the state store itself becomes a tier-zero asset: state contains secrets in plaintext, so whoever reads the blob reads your connection strings. Busy teams hit lock contention. And when reality and state disagree badly, someone gets to perform state surgery with terraform state rm and mv, a task nobody enjoys and few practice.
Bicep is stateless from the user's perspective: ARM's view of live resources is the source of truth. No backend to provision and secure, no lock contention, no surgery. The historical price was that Bicep had no idea what "everything this deployment created" meant, so cleanup was manual. Deployment stacks change that: a stack groups the resources a deployment created, supports delete-on-unmanage semantics, and can deny writes to managed resources. It is not a full state graph, it is Azure-only, and it is younger than Terraform's equivalents, but the "Bicep cannot destroy" objection is now mostly out of date.
The tradeoff, named: Terraform's state buys you a queryable graph of a large estate at the cost of operating and securing that state. Bicep buys freedom from state operations at the cost of weaker whole-estate introspection. Teams under audit sometimes count the missing state backend as a feature in itself: one less secret store to explain.
Provider and Resource Coverage
Bicep gets day-zero coverage of new Azure services because it compiles to ARM and speaks resource-provider API versions directly. The azurerm provider still lags for some services, by days for mainstream ones and occasionally months for niche ones, though 4.x narrowed the gap. Terraform's escape hatch is the azapi provider, which passes raw ARM payloads through Terraform: it works, and you give up typed schemas and clean plans to get it.
Outside Azure the situation inverts completely. Cloudflare, GitHub, Datadog, Grafana, your SaaS vendors: that is Terraform territory, and Bicep does not pretend otherwise. If your platform definition includes anything beyond the Azure resource manager, Bicep alone cannot express it.
Module Ecosystems
- Terraform has the larger public registry by an order of magnitude. Quality varies wildly; the surface area is unmatched.
- Azure Verified Modules is the curated middle path, with Microsoft-maintained modules for common resources, published for both Bicep and Terraform. For Azure-only teams the AVM catalog is often sufficient on its own.
For enterprises, the public registries matter less than they look. Most serious estates converge on a small internal module library either way, and internal module hygiene, versioning, review, ownership, predicts outcomes far better than which registry you started from.
Syntax Matters More Than It Should
Bicep reads cleaner than HCL for Azure resources. It has stronger type inference, user-defined types with compile-time validation, nicer error messages, and an editor experience that feels like writing TypeScript for infrastructure. Terraform's HCL is more mature but shows its age on complex modules: nested dynamic blocks and for-expressions get write-only fast. The same storage account in both:
// Bicep
resource storage 'Microsoft.Storage/storageAccounts@2023-05-01' = {
name: 'st${uniqueString(resourceGroup().id)}'
location: location
sku: { name: 'Standard_LRS' }
kind: 'StorageV2'
properties: {
minimumTlsVersion: 'TLS1_2'
allowBlobPublicAccess: false
}
}
# Terraform equivalent
resource "azurerm_storage_account" "this" {
name = "st${random_string.suffix.result}"
resource_group_name = azurerm_resource_group.this.name
location = var.location
account_tier = "Standard"
account_replication_type = "LRS"
min_tls_version = "TLS1_2"
allow_nested_items_to_be_public = false
}
Notice the Terraform version needs a separate random_string resource and an explicit resource-group reference for what Bicep expresses inline. Multiply that by three hundred resources and syntax stops being cosmetic: it is review time, onboarding time, and the class of bug a new hire introduces in month one.
Drift Detection
Terraform's plan surfaces drift by diffing state against live, and it sees the whole estate in one pass. Bicep detects drift by running what-if against a deployment. It works, with a caveat worth stating plainly: what-if has a reputation for noise, reporting phantom changes on certain resource types where the API returns properties the template never set. It improved steadily through 2025, and it still occasionally cries wolf. Terraform's drift view is more trustworthy at estate scale; Bicep's failure mode is annoyance rather than a corrupted state file. Neither replaces a scheduled reconciliation job in CI, which mature teams run regardless of tool.
CI/CD and Pipelines
Both integrate cleanly with Azure DevOps and GitHub Actions, and both now authenticate the right way: OIDC workload-identity federation to Entra, no long-lived service-principal secrets in the pipeline. Terraform's pattern of plan as a reviewable artifact, then human approval, then apply of that exact plan, is slightly richer than Bicep's what-if output in a PR comment followed by deploy, because the applied change is byte-identical to the reviewed one. Bicep's pipeline has fewer moving parts: no state backend to reach, no lock to hold, no plan artifact to store.
The cost difference is real but small. Terraform needs a state backend (a storage account is effectively free; HCP Terraform is free to 500 resources and a line item after that; Spacelift and friends likewise). Bicep needs nothing. The bigger cost is attention: one more stateful system in the deployment path is one more thing that pages someone.
Testing
- Terraform. The native
terraform testframework (1.6+) covers module contract tests in plain HCL. Terratest remains the integration-test workhorse, tflint catches provider-specific mistakes, and Trivy absorbed tfsec for static security scanning. Mature, if assembled from parts. - Bicep. The linter runs at build,
what-ifserves as deployment preview, and PSRule for Azure checks templates against the Well-Architected baseline before anything deploys. Thinner than Terraform's stack, and for most Azure estates it covers the failures that actually happen.
Migration Cost
Migrating from Terraform to Bicep (or the reverse) is a multi-month project for anything non-trivial: the templates are the easy part, the cutover of live resources and pipeline habits is not. Unless there is a pressing reason, a team that cannot support state operations, an acquisition forcing standardization, a genuine multi-cloud pivot, the migration is rarely worth it. The better move for most teams is to standardize on one tool for new projects and let old projects attrit. If you do make the move, we wrote up the mechanics: Terraform to Bicep migration on Azure, including coexistence patterns for the years both will run side by side.
The Recommendation Matrix
| Your situation | Pick | Why |
|---|---|---|
| Greenfield, Azure-only, small platform team | Bicep | Least operational surface; AVM covers the common resources |
| Greenfield, multi-cloud intent or heavy SaaS providers | Terraform / OpenTofu | The ecosystem is the product; Bicep cannot reach past ARM |
| Brownfield with significant existing Terraform | Stay on Terraform | Migration cost almost never pays back |
| Brownfield with ARM-template inheritance | Bicep | Decompile path from ARM JSON is a weekend, not a quarter |
| Regulated estate, minimal external dependencies | Bicep | No state store holding secrets, one less system in audit scope |
| Org-wide platform team standardizing across clouds | Terraform + AVM's Terraform modules | One language everywhere, Microsoft-curated modules on the Azure side |
The tool matters less than the discipline. A well-run Bicep estate outperforms a neglected Terraform one; the reverse is also true. Pick the one the team will actually keep tidy. For what it is worth, our own default is Bicep for Azure-only builds and Terraform where an estate genuinely spans providers, the same split we apply in migration and platform work.