AZ-104 · Deploy and manage Azure compute resources · Updated August 7, 2026
ARM Templates vs Bicep: Why Bicep Is Now the Recommended Azure IaC Language
Azure Resource Manager (ARM) templates were the original way to declare Azure infrastructure as code, written as JSON documents that Resource Manager reads and deploys. Bicep is what Microsoft now recommends you actually write instead. It isn’t a competing engine, it’s a domain-specific language that compiles down to the exact same ARM JSON template format, which means anything you can deploy with a hand-written ARM template you can also deploy with Bicep, just with far less syntax to fight through. Understanding that relationship, plus how deployment modes and the what-if operation control what actually happens when you deploy, is core to the compute-management domain on the AZ-104 exam.
What an ARM template is
An ARM template is a JSON document with sections for parameters, variables, resources, and outputs. Resource Manager reads it and orchestrates the creation, update, or deletion of every resource it describes, resolving dependencies between resources automatically so they deploy in the correct order, and running independent resources in parallel where possible. The catch is JSON itself: expressions have to be wrapped in bracket syntax like [resourceGroup().location], nested resources require verbose parent/child structures, and a template of any real size becomes hard to read and harder to review in a pull request.
What Bicep is and why Microsoft recommends it
Bicep is a declarative, domain-specific language purpose-built for authoring Azure infrastructure. It isn’t a general-purpose programming language, it exists specifically to describe Azure resources and their properties. Compared to the equivalent JSON, Bicep files are shorter, easier to read, and don’t require bracket-wrapped expressions: you call functions and reference parameters directly. Every resource gets a symbolic name, so referencing one resource from another is a direct reference rather than a chain of resourceId() calls, and Bicep infers most dependency relationships automatically without an explicit dependsOn.
Bicep also gets day-one support for new resource types and API versions, since it’s a transparent layer over ARM JSON rather than a separate product that needs its own update cycle. The Bicep extension for VS Code adds IntelliSense, type-safe validation, and inline documentation while you write, which catches mistakes before you ever run a deployment. None of this changes what gets deployed underneath: Bicep is a more usable way to write ARM, not a replacement engine.
How Bicep relates to ARM under the hood
When you deploy a Bicep file, the Bicep CLI (invoked transparently by Azure CLI, Azure PowerShell, or the Azure portal) transpiles it into a standard ARM JSON template before Resource Manager ever sees it. Every resource type, API version, and property that’s valid in an ARM template is valid in Bicep, because it’s the same underlying schema. This is also why the two are fully interchangeable: you can decompile an existing ARM JSON template into Bicep to start migrating an older template library, and tools like the Bicep Playground let you view a Bicep file and its compiled JSON output side by side.
Deployment modes: Incremental vs Complete
Every template deployment, whether written in ARM JSON or Bicep, runs in one of two modes, and the difference is entirely about what happens to resources in the target resource group that aren’t mentioned in the template.
Incremental is the default and Microsoft’s recommended mode. Resources defined in the template are created or updated, and resources that already exist in the resource group but aren’t in the template are left alone. One nuance worth remembering: when Incremental mode updates an existing resource, it reapplies the full set of properties defined in the template rather than merging changes, so any property you omit gets reset to its default rather than left as-is.
Complete mode deletes any resource that exists in the resource group but isn’t defined in the template, in addition to creating and updating the resources that are. If your resource group has Resources A, B, and C, and your template defines A, B, and D, a Complete-mode deployment leaves A, B, and D in place and deletes C. That deletion behavior is exactly why Complete mode is risky in practice: a typo, a forgotten resource block, or an out-of-band resource someone created manually can all get silently removed.
| Incremental | Complete | |
|---|---|---|
| Resources in template | Created or updated | Created or updated |
| Resources not in template | Left unchanged | Deleted |
| Default mode | Yes | No |
| Supported at subscription level | Yes | No |
| Microsoft’s current recommendation | Preferred for all deployments | Being phased out in favor of deployment stacks |
Deployment stacks are now recommended over Complete mode
Current Microsoft Learn guidance is explicit that Complete mode is being gradually deprecated, and that deployment stacks are the recommended way to manage resource deletions going forward. A deployment stack (Microsoft.Resources/deploymentStacks) wraps a Bicep file or ARM JSON template as a managed unit at resource group, subscription, or management group scope, similar to how management groups, subscriptions, and resource groups nest scopes for governance. When you remove a resource from the underlying template and redeploy the stack, that resource can be detached or deleted depending on the actionOnUnmanage setting you choose (deleteAll, deleteResources, or detachAll), giving you the same cleanup capability Complete mode offered, but as an explicit, auditable decision rather than an implicit side effect of every deployment.
Deployment stacks add a second capability Complete mode never had: deny settings. Setting denySettingsMode to denyDelete or denyWriteAndDelete creates a deny assignment that blocks unauthorized principals from deleting or modifying the stack’s managed resources outside of the stack itself, similar in spirit to how resource locks protect individual resources, except deny settings apply to an entire managed group of resources at once and are scoped to the deployment mechanism itself.
The what-if operation
Before you deploy anything, in either mode, the what-if operation lets you preview exactly what will change without making any changes. Running a deployment with -WhatIf in Azure PowerShell or az deployment group what-if in Azure CLI returns a list of every affected resource tagged with a change type: Create for new resources, Modify for resources whose properties will change, Delete for resources Complete mode will remove, NoChange for resources being redeployed with identical properties, and Ignore for resources outside the template that Incremental mode won’t touch. Microsoft’s own guidance is to always run what-if before any Complete-mode deployment specifically because it’s the only reliable way to confirm what’s about to be deleted before it happens; the same discipline applies to deleteAll operations on a deployment stack.
How the AZ-104 exam tests this
- Choosing Bicep vs ARM JSON for a new project. Scenarios describing a team that wants concise syntax, built-in type checking, or day-one support for new resource types are pointing at Bicep. Remember that Bicep and ARM JSON produce identical deployment results, since Bicep transpiles to JSON before Resource Manager ever runs it.
- Predicting the outcome of Incremental vs Complete mode. Expect a resource-group inventory and a template’s resource list, then a question asking what remains after deployment. Incremental never deletes; Complete deletes anything not listed, subject to which resource types support Complete-mode deletion.
- Recognizing when deployment stacks are the better tool. A scenario needing resource deletion as part of routine deployment, or needing to block accidental changes to a group of managed resources, should point you toward deployment stacks rather than Complete mode, in line with current Microsoft guidance.
- Reading what-if output. Expect to match a change symbol (Create, Modify, Delete, NoChange, Ignore) to what will actually happen, and to know that what-if never makes changes itself, it only predicts them.
- Deployment scope questions. Bicep files, ARM templates, and deployment stacks can all target resource group, subscription, or management group scope, and the exam may ask which scopes support which deployment mode (Complete mode, notably, isn’t supported at the subscription level).
For the broader governance and resource-organization picture that deployment scopes build on, see the AZ-104 study guide.