Backend / Cloud: Azure / 04_bicep_and_iac.md

Bicep and infrastructure as code on Azure

Updated 5 interview angles 4 min read source
On this page6
  1. What Bicep is
  2. Bicep versus Terraform
  3. What-if, the equivalent of plan
  4. Modules
  5. Related
  6. Interview angle

Bicep and infrastructure as code on Azure

Azure has three IaC options and the interview question is which you would pick. The short answer: Bicep for Azure-only, Terraform when the estate is not.

What Bicep is

Bicep is a domain-specific language that compiles to ARM templates. ARM is Azure’s native deployment format - JSON, verbose, and unpleasant to write by hand. Bicep is the same model with a readable syntax.

bicep
param location string = resourceGroup().location

resource plan 'Microsoft.Web/serverfarms@2023-01-01' = {
  name: 'api-plan'
  location: location
  sku: { name: 'P1v3' }
}

resource site 'Microsoft.Web/sites@2023-01-01' = {
  name: 'api-prod'
  location: location
  properties: { serverFarmId: plan.id }
}

Two things follow from compiling to ARM rather than being its own engine:

  • No state file. Azure Resource Manager already knows what exists, so Bicep asks it rather than keeping a record. This removes Terraform’s whole class of state problems - locking, drift between state and reality, secrets sitting in plaintext in the state file.
  • Same-day resource support. Because it targets ARM directly, a new Azure resource is usable immediately, rather than waiting for a provider release.

Referencing plan.id creates an implicit dependency, so ordering is derived rather than declared - the same idea as Terraform’s graph.

Bicep versus Terraform

Bicep Terraform
Scope Azure only Multi-cloud
State None; ARM is the record State file to manage
New services Immediate Waits for the provider

The decision is rarely about the languages. It is about the estate. A team already running Terraform for AWS or Cloudflare should not adopt a second tool and a second set of habits for the Azure slice. A team wholly on Azure gets a simpler operational story with Bicep, mostly by not having state to look after.

The third option, ARM templates directly, is legacy. Write Bicep and let it compile; you can always inspect the ARM output.

What-if, the equivalent of plan

The reviewable diff before applying:

bash
az deployment group what-if \
  --resource-group prod \
  --template-file main.bicep

Run it in the pipeline on a merge request so a human sees the change before it happens. This is the same discipline as terraform plan in CI, and it is the control that makes infrastructure changes reviewable - see CloudFormation vs Terraform.

what-if is less precise than terraform plan: it sometimes reports properties as changing when they will not, because it compares against the resource’s full declared shape. Treat noisy lines as noise, but never treat a deletion as noise.

Deployment modes

The setting that causes accidents. Incremental (the default) leaves resources not mentioned in the template alone. Complete deletes anything in the resource group that the template does not declare.

Complete mode makes the template genuinely authoritative, which is what you want for a managed environment - and it will delete a resource someone created by hand in the portal. That is the point, and it is also why you run what-if first.

Modules

Bicep modules are files you invoke with parameters, the same composition idea as a Terraform module:

bicep
module api 'modules/webapp.bicep' = {
  name: 'api'
  params: {
    appName: 'api-prod'
    skuName: 'P1v3'
  }
}

Keep environments as parameter files over one module set rather than copied templates per environment. Copied templates drift, and the drift is discovered during an incident when staging and production turn out not to match.

Interview angle 5

  • “Bicep or Terraform on Azure?” - Bicep if the estate is Azure-only, because there is no state file to manage and new resources are supported the day they ship. Terraform if anything else is in the estate, since running one tool and one set of habits beats a per-cloud split.
  • “Why does Bicep not need a state file?” - it compiles to ARM, and Azure Resource Manager already records what exists, so the desired state is compared against the platform rather than a local record. That removes state locking, state drift, and secrets in plaintext state.
  • “What is the equivalent of terraform plan?” - az deployment group what-if, run in CI on a merge request so the diff is reviewed before apply. It is noisier than Terraform’s plan and can report properties as changing when they will not, but a reported deletion should never be dismissed.
  • “What is the difference between incremental and complete mode?” - incremental leaves undeclared resources alone; complete deletes anything in the resource group the template does not declare. Complete makes the template authoritative and will remove resources someone created in the portal.
  • “How do you handle multiple environments?” - one module set with per-environment parameter files, not copied templates. Copies drift, and the drift surfaces during an incident when staging turns out not to match production.