The Bicep X-Ray: Why Great Developers Read the Assembly Code

Mid/Senior Engineer Asked at: Microsoft, any company on Azure

Q: You've written a Bicep file. How do you inspect the underlying ARM JSON it generates, and why would you ever need to do this?

Why this matters: This question tests your ability to navigate levels of abstraction. A junior engineer lives entirely within the high-level language. A senior engineer knows when and how to peel back the layers to debug the fundamental reality underneath. It's a test of your diagnostic depth.

Interview frequency: High for any role involving Azure IaC.

❌ The Death Trap

The candidate simply states the command without providing any strategic reason for using it. They treat it as a novelty, not a critical tool.

"You can use the Azure CLI command `az bicep build --file `. It will create a JSON file with the same name. You would do it to see what the ARM template looks like."

This is a low-value, mechanical answer. It answers the "how" but completely misses the much more important "why."

🔄 The Reframe

What they're really asking: "Do you understand that Bicep is a transparent abstraction, not a magic box? When a deployment fails with a cryptic error from the Azure control plane, do you have the tools and mental model to debug the 'compiled' code that the machine is actually executing?"

This reframes the command from a simple utility into a powerful diagnostic tool. It's about demonstrating your ability to reason about the entire toolchain, not just the part you wrote.

🧠 The Mental Model

The "View Compiled Assembly" model. Great programmers understand the relationship between their high-level code and the low-level machine code it produces.

1. Bicep is your Python/C#: It's the clean, human-readable language you work in 99% of the time.
2. ARM JSON is the Assembly Code: It's the verbose, machine-optimized language that the Azure Resource Manager (the CPU) actually executes.
3. `az bicep build` is the Decompiler/Disassembler: It's the expert tool you use when you have a strange bug that you can't explain at the high level. It lets you look "under the hood" to see exactly what instructions your elegant code was translated into.

✅ The Answer

The Principle: Trust, but Verify Your Abstractions

The entire value of Bicep is its elegant abstraction over ARM JSON. But every abstraction has the potential to become a "leaky" or confusing black box. The `az bicep build` command is the essential tool for turning that black box into a glass box. It's our X-ray machine.

The command itself is simple, assuming you have the Azure CLI installed:

# This command reads storage.bicep and writes storage.json az bicep build --file storage.bicep

But the *reason* we use this command is far more important than the syntax.

Why We Need the X-Ray: A Debugging Story

Imagine this scenario: you're deploying a Bicep file with a complex module structure. The deployment fails with a cryptic error from Azure like `Deployment failed with a conflict on resource property 'networkAcls'`. You look at your Bicep code, and you're not setting that property anywhere. You're stuck.

This is when you use the X-ray. You run `az bicep build`. By inspecting the generated ARM JSON, you might discover that a nested module you're using *is* setting a default value for `networkAcls`, and it's conflicting with another resource. This issue was completely invisible at the Bicep level but becomes immediately obvious when you inspect the "compiled assembly."

It transforms the debugging process from guesswork into a systematic analysis of the final payload being sent to the Azure API.

The Side-by-Side Reality

Bicep: The Intent

// 5 lines of clear, human intent resource stg 'Microsoft.Storage/storageAccounts@2021-09-01' = { name: 'bicepdemostore123' location: 'eastus' sku: { name: 'Standard_LRS' } kind: 'StorageV2' }

ARM JSON: The Reality

// The verbose machine reality { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "...", "templateHash": "..." } }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2021-09-01", "name": "bicepdemostore123", "location": "eastus", "sku": { "name": "Standard_LRS" }, "kind": "StorageV2" } ] }

🎯 The Memorable Hook

This connects the practical command to a deep, first-principles concept about the nature of software abstractions and the power of being able to move between them.

💭 Inevitable Follow-ups

Q: "What about the reverse? Can you turn a legacy ARM template into Bicep?"

Be ready: "Absolutely, and that's another critical use case. The command is `az bicep decompile`. It's an incredibly powerful tool for modernizing an existing IaC codebase. While the output isn't always perfect and may require some manual cleanup, it does about 90% of the work in converting a verbose, hard-to-maintain JSON file into a clean, readable Bicep file. It's the key to paying down technical debt."

Q: "Is there a way to see this transpiled JSON during a live deployment without building the file locally?"

Be ready: "Yes. After a deployment is complete, you can go to the specific deployment in the Azure Portal, within the resource group. The 'Template' blade will show you the exact ARM JSON that was processed by the Resource Manager. This is the ultimate source of truth for what Azure actually executed, making it another vital tool for post-mortem debugging."

Written by Benito J D