👋Hi, I'm Waqas — a Software Architect and Technical Consultant specializing in .NET, Azure, microservices, and API-first system design..
I help companies build reliable, maintainable, and high-performance backend platforms that scale.
Bicep for Azure: modules, parameters, deployment. Bicep vs ARM vs Terraform.
March 5, 2024 · Waqas Ahmad
Read the article
Introduction
This guidance is relevant when the topic of this article applies to your system or design choices; it breaks down when constraints or context differ. I’ve applied it in real projects and refined the takeaways over time (as of 2026).
Managing Azure infrastructure by hand does not scale and leaves no audit trail or repeatability. This article explains Bicep—Microsoft’s DSL for Azure IaC—including syntax, modules, parameters, deployment, and when to choose Bicep over ARM or Terraform. For architects and platform engineers, IaC with Bicep gives versioned, reviewable infrastructure and consistent deployments across environments.
System scale: Bicep applies from single-resource scripts to large multi-module deployments; typical use is resource groups or subscriptions with parameterised environments.
Team size: Any team that owns Azure infrastructure; often DevOps or platform engineers; developers may author modules with review.
Time / budget pressure: IaC pays off when you deploy repeatedly or need consistency; one-off manual setup may be faster short-term but doesn’t scale.
Technical constraints: Azure-only; .NET/CI pipelines (Azure DevOps, GitHub Actions) for deployment. Multi-cloud or heavy non-Azure use → consider Terraform.
Non-goals: This article does not cover Terraform in depth, or advanced ARM/Bicep patterns (nested deployments, deployment scripts); boundaries are stated where they matter.
What is Infrastructure as Code?
IaC means defining infrastructure (VMs, databases, networks, storage) in code files that can be:
Versioned: Track changes in Git
Reviewed: Pull requests for infrastructure changes
Tested: Validate before deployment
Deployed repeatably: Same template, same result
Benefit
Description
Consistency
Same resources every time
Repeatability
Deploy to dev, test, prod with same template
Audit trail
Git history shows who changed what
Speed
Automated deployments vs manual clicking
Disaster recovery
Rebuild infrastructure from code
What is Bicep?
Bicep is a DSL for deploying Azure resources. It compiles to ARM JSON but is:
Concise: Less verbose than ARM JSON
Readable: Clean syntax, no nested brackets
Type-safe: IntelliSense in VS Code
Native: First-class support in Azure CLI and Azure DevOps
Need non-Azure providers (Kubernetes, Datadog, etc.)
Team already knows Terraform
Bicep syntax basics
Bicep files declare resources (e.g. storage, web app) with a simple, declarative syntax; you can add parameters and variables to avoid repetition and support multiple environments.
# Deploy to resource group
az deployment group create --resource-group my-rg --template-file main.bicep --parameters parameters.dev.json
# What-if (preview changes)
az deployment group what-if --resource-group my-rg --template-file main.bicep --parameters parameters.prod.json
7. Validate in CI. Use az bicep build to catch errors before deployment.
8. Document modules. Add comments; create a README for your infra folder.
Common issues
Issue
Cause
Fix
Deployment fails
Syntax error, invalid API version
Run az bicep build locally
Resource already exists
Name collision
Use unique naming (e.g. uniqueString())
Drift
Manual portal changes
Deploy only from code; use Policy
Secrets in repo
Connection strings committed
Use Key Vault; pipeline variables
Large single file
Hard to maintain
Split into modules
Wrong API version
Deprecated or missing properties
Check Azure docs for current version
Summary
Bicep is the recommended way to write Azure IaC: concise, type-safe, and integrated with Azure CLI and DevOps; use modules, parameter files, and CI/CD for repeatable deployments. Getting this right gives you versioned infrastructure and consistent environments instead of drift and manual fixes. Next, parameterise one existing resource group or app and add a single Bicep module to your pipeline so the pattern is in place before scaling out.
Position & Rationale
I use Bicep for Azure-only infrastructure when we want the simplest path: native tooling, no state file, compiles to ARM. I prefer modules for reusability and parameter files per environment so we don’t duplicate templates. I deploy via CI/CD (Azure DevOps or GitHub Actions) so every change is versioned and repeatable. I choose Terraform when we need multi-cloud or non-Azure providers; I don’t use Bicep for that. I avoid secrets in repo—use Key Vault references or pipeline variables. I reject deploying from the portal once IaC is in place; drift makes the codebase a lie. For small or one-off Azure setups, a single Bicep file may be enough; for enterprise I use modules, naming (e.g. uniqueString()), and Policy to prevent manual drift.
Trade-Offs & Failure Modes
What this sacrifices: Bicep is Azure-only; no state management (unlike Terraform)—Azure Resource Manager is the source of truth. Learning and tooling are Azure-centric.
Where it degrades: When people deploy manually and drift accumulates; when secrets are committed; when a single huge file is unmaintainable; when API versions are wrong or deprecated.
How it fails when misapplied: Using Bicep for multi-cloud—wrong tool. Committing connection strings or keys. No parameterisation so dev/prod differ by hand. Skipping what-if or validation so broken templates reach the pipeline.
Early warning signs: “We’re not sure what’s actually deployed”; “someone changed it in the portal”; “our Bicep file is 2000 lines”; “deployments keep failing with name conflicts.”
What Most Guides Miss
Guides often show a single file and skip modules and parameter files—in practice, reusability and environment separation (dev/test/prod) require both. Drift (manual changes in the portal) is underplayed; without Policy or discipline, the code and reality diverge. Secrets—Key Vault references vs pipeline variables—and naming (uniqueString(), naming conventions) to avoid collisions are rarely stressed. what-if and validation (az bicep build) before merge are easy to skip; they catch errors early.
Decision Framework
If you’re on Azure only and want simple IaC → Use Bicep; modules and parameters; deploy via CI/CD.
If you need multi-cloud or non-Azure providers → Use Terraform; Bicep is not the right fit.
If you have multiple environments → Use parameter files per environment; never hardcode env-specific values in the template.
If you have secrets → Key Vault references or pipeline variables; never commit secrets.
If drift is a problem → Deploy only from code; use Azure Policy to restrict manual creation/changes where possible.
If the template is huge → Split into modules; one concern per file.
Bicep for Azure-only IaC; modules and parameter files for reusability and environments; deploy via CI/CD; no secrets in repo.
Use what-if and az bicep build before merge; use uniqueString() and naming conventions to avoid collisions; prevent drift by deploying only from code.
Revisit Bicep vs Terraform when multi-cloud or non-Azure needs appear.
When I Would Use This Again — and When I Wouldn’t
I would use Bicep again for any Azure-only infrastructure that we version and deploy via pipeline—resource groups, app services, storage, SQL, etc. I’d use modules and parameters from day one. I wouldn’t use Bicep for multi-cloud or when we need non-Azure providers (e.g. Kubernetes, Datadog)—Terraform is the right choice there. I wouldn’t deploy from the portal once we have Bicep; I’d treat drift as a failure. For a one-off lab or throwaway env, a single Bicep file might be enough; for anything that outlives a sprint, I’d add CI/CD and parameter files. If the team can’t own Git and pipelines, I’d still write Bicep and treat automation as a prerequisite for production.
Frequently Asked Questions
Frequently Asked Questions
What is IaC?
Infrastructure as Code means defining infrastructure in code files that are versioned, reviewed, and deployed repeatably.
What is Bicep?
Bicep is Microsoft’s DSL for Azure IaC. It compiles to ARM JSON but is easier to write and read.
Bicep vs ARM JSON?
Bicep is concise and readable. ARM JSON is verbose. Bicep compiles to ARM, so you get the same deployment.
Bicep vs Terraform?
Use Bicep for Azure-only. Use Terraform for multi-cloud or non-Azure providers.
How do I deploy Bicep?
az deployment group create --template-file main.bicep --parameters parameters.json
What are modules?
Reusable Bicep files that you reference from your main template. Split templates into logical units.
How do I handle secrets?
Never commit secrets. Use Key Vault references or inject via pipeline variables.
What is what-if?
Preview command that shows what changes will be made without actually deploying.
How do I validate Bicep?
az bicep build --file main.bicep compiles and validates syntax.
Can I convert ARM to Bicep?
Yes. az bicep decompile --file template.json converts ARM JSON to Bicep.