Bicep

Also known as: Azure Bicep

On this page 7

Bicep is a declarative domain-specific language for deploying Microsoft Azure resources, and within infrastructure as code it serves as the native, more readable alternative to raw Azure Resource Manager (ARM) JSON templates. A Bicep file describes the desired end state of resources such as virtual networks, storage accounts and app services, and the Azure deployment engine works out how to reach that state.

Bicep, also called Azure Bicep, is a transparent abstraction over ARM: every file compiles to an ARM template, so anything ARM can deploy, Bicep can deploy, usually on the day a new resource type or API version ships. In the Cloud subject it sits beside Terraform, Pulumi and AWS CloudFormation as one of the main tools for repeatable, version-controlled environments.

How Bicep compiles and deploys

Bicep works as a source-to-source compiler: the Bicep CLI, bundled with the Azure CLI and Azure PowerShell, transpiles a .bicep file into ARM JSON, and Azure Resource Manager performs the actual deployment. The engineer never has to maintain the generated JSON, which is treated as a build artifact.

A crucial design choice is that Bicep keeps no state file. The live Azure environment is the source of truth, so Resource Manager compares the template with what already exists in the target scope and creates or updates resources accordingly. This removes state locking and state corruption problems, but it also means drift detection depends on Azure features such as what-if previews rather than on a stored snapshot.

The deployment pipeline follows a fixed sequence of stages, summarized below.

StageWhat happensTool or service
AuthoringResources, parameters and modules are written in .bicep filesEditor with the Bicep language server
LintingBuilt-in rules flag unused parameters, hard-coded locations and secretsBicep linter, configured in bicepconfig.json
BuildThe file is transpiled into an ARM JSON templateaz bicep build or implicit build on deploy
PreviewPredicted creates, modifications and deletions are listedaz deployment group what-if
DeploymentResource Manager orchestrates resources in dependency orderAzure Resource Manager
Stages of a Bicep deployment

Core language elements

The Bicep language is small and strongly typed. A resource declaration names a symbolic identifier, a resource type and an API version such as Microsoft.Storage/storageAccounts@2023-05-01, followed by its properties. Referencing one resource’s property from another creates an implicit dependency, so explicit dependsOn lists are rarely needed.

ElementKeywordPurpose
ParameterparamInput supplied at deployment time, with optional decorators such as @allowed or @secure
VariablevarComputed value reused within the file
ResourceresourceDeclares an Azure resource and its properties
ModulemoduleCalls another Bicep file as a reusable unit
OutputoutputReturns values such as resource IDs to callers
Existing referenceexistingReads a resource deployed elsewhere without managing it
User-defined typetypeDescribes structured parameter shapes for validation
Main building blocks of a Bicep file

Loops use for expressions to create several instances from an array, and conditions use the if keyword to deploy a resource only when a parameter allows it. Parameter values can live in a separate .bicepparam file, which keeps one template reusable across development, test and production environments.

Deployment scopes and modules

Every Bicep file declares a target scope, which decides where its resources land. The default is a resource group, but the same language also deploys at subscription, management group and tenant level, which matters for governance artifacts such as policy assignments and role definitions.

Modules are the main unit of reuse. A module can be a local file, a module published to an Azure Container Registry as an OCI artifact, or a template spec stored in Azure. The community-maintained Azure Verified Modules library provides tested modules for common resource types, which shortens the path from a blank file to a production-ready configuration.

Newer features extend the model further. Deployment stacks group the resources from one deployment so that resources removed from the template can be detached or deleted on the next run, which addresses the long-standing gap of orphaned resources in incremental deployments.

Bicep compared with other infrastructure as code tools

The main choice teams face is between Azure-only depth and multi-cloud reach. The comparison below shows how Bicep differs from its closest neighbors in the Topic.

AspectBicepARM JSONTerraformPulumi
Cloud coverageAzure onlyAzure onlyMulti-cloud through providersMulti-cloud through providers
LanguageDeclarative DSLVerbose JSONHCLGeneral-purpose languages
State handlingNo state fileNo state fileExplicit state fileExplicit state backend
New Azure featuresSame day as ARMSame dayAfter provider updateAfter provider update
Preview of changesWhat-ifWhat-ifPlanPreview
Bicep and related tools

Teams that run almost everything on Azure often prefer Bicep because no extra runtime or state backend is required and support for new services is immediate. Organizations with workloads across several clouds usually standardize on Terraform or OpenTofu instead, accepting the overhead of managing state in exchange for one workflow across providers.

Practical pitfalls and good habits

Bicep reduces syntax errors, but several operational traps remain. Most of them come from the incremental deployment mode and from the fact that Resource Manager validates some properties only at deployment time.

ProblemCauseRemedy
Resources left behindIncremental mode ignores items removed from the fileUse deployment stacks or controlled cleanup
Accidental deletionComplete mode removes anything not in the templateRun what-if and restrict complete mode
Secrets in outputsOutputs are stored in deployment historyMark parameters @secure and read secrets from Key Vault
Outdated API versionsCopied snippets pin old versionsEnable the linter rule for recent API versions
Manual portal changesEdits outside the pipeline cause configuration driftRedeploy regularly and restrict write access
Common problems and how to avoid them

A sound workflow keeps Bicep files in Git, runs lint and what-if in pull requests, and deploys only from a pipeline identity. Combined with policy as code through Azure Policy, this gives a reviewable and auditable path for every infrastructure change.

The short version

Bicep is a way to describe Azure cloud resources in a short text file instead of clicking through a web portal. You write down what you want to exist, such as a network, a database and a web app, and Azure builds it for you.

Because the description is a file, it can be saved, reviewed and reused. Running the same file again produces the same environment every time, much like following an exact recipe rather than cooking from memory.

Where it makes a difference

A software team at a mid-sized insurer runs its customer portal on Azure in three environments: development, test and production. Previously each environment was configured by hand in the portal, and small differences in firewall rules and app settings caused failures that appeared only in production.

The team rewrote the setup as one main Bicep file with modules for networking, App Service, Azure SQL and Key Vault, plus one .bicepparam file per environment. Every pull request now runs the linter and a what-if preview, and the pipeline deploys after approval. Building a new test environment dropped from about two days of manual work to under twenty minutes, and the configuration differences between environments disappeared because all three come from the same template.