---
cuppy_hub: azure
cuppy_path: patterns/alternatives/terraform-azurerm.md
cuppy_section: docs
cuppy_doc: MFS5-8126
cuppy_doc_uuid: e5880809-db40-44a8-9ea8-4d09f2fd21b2
cuppy_permalink: https://cuppy.io/azure/d/MFS5-8126
cuppy_version: 1
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/azure/docs/patterns/alternatives/terraform-azurerm
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: 0aff3b675e1bc217427124e9dcffae5b4a7c28a9b48350253f750c8d92ae2ce1
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# Terraform (azurerm) as the alternative to Bicep

## When to pick which

| Pick | When |
|---|---|
| **Bicep** | Azure only. You want no state file to host and lock, day-one support for new API versions (once Bicep has the types), what-if, and deployment stacks for deletion and deny settings |
| **Terraform `azurerm`** | You already run Terraform, manage several clouds or SaaS providers in one plan, or want plan/apply with state-based drift detection |

Both call the same Resource Manager APIs, so the ARM error catalogues (`reference/arm/errors.md`, `reference/arm/deployment-errors.md`) and the RBAC and policy documents apply unchanged. Terraform adds its own state and provider-configuration failures.

## Provider configuration that works (azurerm 5.x)

- `features {}` block: **required**.
- `subscription_id`: **required for `plan` and `apply`** (not for `validate`). Set it, or `ARM_SUBSCRIPTION_ID`.
- **Resource providers:** since v5 the default `resource_provider_registrations` is `none`, so nothing is registered for you. Either set `resource_provider_registrations = "legacy"` (the v4 behaviour) or list the providers in `resource_providers_to_register`, or register them once with `az provider register`.
- **Authentication:**
  - From GitHub Actions: `use_oidc = true` (or `ARM_USE_OIDC=true`) with `ARM_CLIENT_ID` and `ARM_TENANT_ID`. The provider reads `ACTIONS_ID_TOKEN_REQUEST_URL` / `_TOKEN` itself, and the job needs `permissions: id-token: write`. The federated credential rules are the same as for `azure/login` (`reference/entra/federated-credential-errors.md`).
  - On Azure compute: `use_msi = true`.
  - Locally: the Azure CLI (`use_cli`, on by default).
- `storage_use_azuread = true` makes the provider use Entra ID instead of shared keys for blob and queue data. Leave it at the default `false` and the provider needs storage account keys, which fails when shared-key access is disabled.

## Known-bad

| Configuration | Symptom |
|---|---|
| A v4 configuration upgraded to v5 unchanged | `MissingSubscriptionRegistration` for providers v4 used to register |
| No `subscription_id` anywhere | `plan` fails; `validate` passes, which hides it until CI |
| `use_oidc` without `id-token: write` in the workflow | The provider can't get a GitHub token (the same failure as `azure/login`) |
| Several federated credentials on one user-assigned identity, provider older than 3.40.0 | 409 conflicts: older versions created them concurrently |
| Role assignments with `name` unset and principals recreated | Duplicate or conflicting assignments (`RoleAssignmentExists`, `RoleAssignmentUpdateNotPermitted`): the same causes as in Bicep (`reference/rbac/errors.md`) |
| Shared-key access disabled on the storage account, `storage_use_azuread` false | Data-plane operations on containers or queues fail with authorization errors (storage family) |

The provider's own pages are the reference for resource arguments. This hub only covers what an agent gets wrong when moving between the two tools.


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 107 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/azure/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
