Logo
CloudWithSingh
Back to all field notes
Concept Map
Azure
Beginner

Azure Bicep Learning Roadmap — From First Template to Production Deployments

A structured, hands-on learning path for Azure Bicep. Five phases that take you from writing your first template to managing production infrastructure with deployment stacks, conditions, and loops.

Parveen Singh
March 11, 2026
14 min read
Prerequisites:An Azure account (free tier works)Azure CLI installed (az --version to check)VS Code with the Bicep extension installedBasic understanding of Azure resource groups and services
TLDR

Azure Bicep is Microsoft's domain-specific language for deploying Azure infrastructure as code. This roadmap takes you from writing your first template through expressions and parameters, deploying real resources like VNets and VMs, managing resource lifecycles with deployment stacks, and finally writing production-ready code with conditions, loops, and what-if previews. Each phase builds on the last — with a hands-on lab to lock in the skill before you move on.

🗺️ How This Roadmap Works

This isn't a documentation dump. It's a structured learning path designed the way I teach Bicep in my training sessions — concept first, then hands-on, then build.

Each phase follows this pattern:

  • 📚 Understand the concept — what it is and why it matters
  • 🧪 Do the lab — hands-on practice in a real Azure environment
  • 🏗️ Apply it — what you should be able to build after this phase
  • Checkpoint — how to know you're ready to move on

Estimated total time: 2–3 weeks at 1–2 hours per day. If you already work with ARM templates or Terraform, you'll move faster.

Pro Tip

Don't skip phases. I've seen engineers jump straight to deployment stacks and get confused because they didn't build the muscle memory for parameters and expressions first. Each phase takes less than a day — invest the time.

🧭 Why Bicep (and Why Now)

If you work in Azure, Bicep should be in your toolkit. Here's why:

ARM Templates / PortalBicep
JSON — verbose, hard to readClean, concise syntax
No native modularityFirst-class module support
Manual dependency managementAutomatic dependency detection
Copy-paste between environmentsParameters + expressions = reusable
No deployment lifecycle managementDeployment stacks manage full lifecycle

Bicep compiles down to ARM templates, so you get the same deployment engine — but with a language that's actually pleasant to write. And unlike Terraform, there's zero state file management. Azure IS the state.

Every AZ-104, AZ-400, and AZ-305 exam now expects you to understand Bicep. More importantly, every Azure job posting in 2026 lists IaC as a requirement. This is the skill that separates "I know Azure" from "I can build and ship in Azure."


🚀 Phase 1: Write and Deploy Your First Template

⏱️ Time: 2–3 hours | 🎯 Goal: Deploy a real Azure resource using Bicep

Before you can build anything complex, you need to understand the fundamentals: how a Bicep file is structured, how to deploy it, and what happens under the hood.

What You'll Learn

ConceptWhy It Matters
Bicep file structureEvery .bicep file follows the same pattern — resources, parameters, outputs
Resource declarationsThe core building block — resource keyword + symbolic name + type + properties
The deployment workflowaz deployment group create — the command you'll run hundreds of times
What Bicep compiles toUnderstanding that Bicep → ARM JSON helps you debug issues

The Core Pattern

Every Bicep deployment follows this flow:

write .bicep file → az deployment group create → Azure Resource Manager → resources created

Your first template should be simple — a storage account is perfect. It has minimal required properties but teaches you the full deployment cycle.

// main.bicep — your first template
param location string = resourceGroup().location
param storageAccountName string = 'stdemobicep${uniqueString(resourceGroup().id)}'
 
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
}
 
output storageId string = storageAccount.id

Then deploy it:

az deployment group create \
  --resource-group rg-bicep-demo \
  --template-file main.bicep

That's it. You just deployed infrastructure as code.

🧪 Hands-On Lab

Lab: Write & Deploy Your First Bicep Template
Hands-on Lab

Lab: Write & Deploy Your First Bicep Template

Start from scratch — create a Bicep file, understand the syntax, and deploy your first Azure resource. This is where your IaC journey starts.

cloudlearn.ioStart Lab

✅ Phase 1 Checkpoint

You're ready for Phase 2 when you can:

  • Create a .bicep file from scratch without copying from docs
  • Explain what resource, param, and output do
  • Deploy a template using az deployment group create
  • Find and read the deployment output in the terminal

🔧 Phase 2: Expressions, Parameters, Variables, and Outputs

⏱️ Time: 3–4 hours | 🎯 Goal: Write reusable, flexible templates

Phase 1 got you deploying. Phase 2 makes your templates smart. This is where Bicep stops feeling like a chore and starts feeling powerful.

What You'll Learn

ConceptWhy It Matters
ParametersAccept input values — makes templates reusable across environments
VariablesCompute values once, reference them everywhere — keeps templates DRY
OutputsReturn values after deployment — critical for chaining deployments
Expressions & functionsuniqueString(), resourceGroup().location, string interpolation — the glue that makes Bicep flexible
Decorators@allowed, @minLength, @description — add validation and documentation inline

Why This Phase Matters

Without parameters and variables, every environment gets a separate template. That's a maintenance nightmare. With them, you write one template and deploy it to dev, staging, and production by changing a parameter file.

// parameters make templates reusable
@allowed(['dev', 'staging', 'prod'])
param environment string
 
@description('The Azure region for all resources')
param location string = resourceGroup().location
 
// variables compute values from parameters
var storageName = 'st${environment}${uniqueString(resourceGroup().id)}'
var skuName = environment == 'prod' ? 'Standard_GRS' : 'Standard_LRS'
 
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = {
  name: storageName
  location: location
  sku: {
    name: skuName
  }
  kind: 'StorageV2'
  tags: {
    environment: environment
  }
}
 
// outputs let you reference deployed resource properties
output storageEndpoint string = storageAccount.properties.primaryEndpoints.blob

Notice how the same template handles dev (cheap, LRS) and prod (geo-redundant, GRS) — just by changing the environment parameter.

🧪 Hands-On Lab

Lab: Bicep Expressions, Parameters, Variables & Outputs
Hands-on Lab

Lab: Bicep Expressions, Parameters, Variables & Outputs

Build templates that adapt to different environments using parameters, variables, built-in functions, and outputs. The foundation for every real-world Bicep project.

cloudlearn.ioStart Lab

✅ Phase 2 Checkpoint

You're ready for Phase 3 when you can:

  • Create a parameter with validation decorators (@allowed, @minLength)
  • Use uniqueString() and string interpolation to generate resource names
  • Explain the difference between a parameter and a variable
  • Deploy the same template to two different environments using parameter values

🏗️ Phase 3: Deploy Real Infrastructure — VNets and VMs

⏱️ Time: 3–4 hours | 🎯 Goal: Deploy multi-resource infrastructure with dependencies

Deploying a storage account proves you can use Bicep. Deploying a VNet with subnets and a VM proves you can build real infrastructure. This is the phase where your templates start looking like something you'd actually use at work.

What You'll Learn

ConceptWhy It Matters
Multi-resource templatesReal deployments have 5, 10, 50+ resources — you need to organize them
Resource dependenciesBicep auto-detects most dependencies, but you need to understand when (and why) to use dependsOn
Networking resourcesVNets, subnets, NSGs, NICs, public IPs — the networking stack you'll deploy in every project
Virtual machinesThe most common Azure resource — combining compute, storage, and networking
Resource referencesUsing existingResource.id to wire resources together

The Real-World Pattern

In practice, a VM deployment isn't one resource — it's a stack:

VNet → Subnet → NSG → Public IP → NIC → VM

Bicep handles the dependency graph automatically when you reference one resource inside another. That's one of its biggest advantages over ARM JSON, where you had to manually specify dependsOn for everything.

// Bicep figures out that the NIC depends on the subnet
// because you referenced subnet.id in the NIC properties
resource nic 'Microsoft.Network/networkInterfaces@2023-11-01' = {
  name: 'nic-${vmName}'
  location: location
  properties: {
    ipConfigurations: [
      {
        name: 'ipconfig1'
        properties: {
          subnet: {
            id: vnet.properties.subnets[0].id  // ← implicit dependency
          }
          privateIPAllocationMethod: 'Dynamic'
        }
      }
    ]
  }
}

No dependsOn needed. Bicep sees the reference and orders the deployment correctly.

🧪 Hands-On Lab

Lab: Deploy a Virtual Network & VM Using Bicep
Hands-on Lab

Lab: Deploy a Virtual Network & VM Using Bicep

Build a complete networking stack and deploy a virtual machine — VNet, subnet, NSG, public IP, NIC, and VM — all in one Bicep template. This is what real Azure infrastructure looks like.

cloudlearn.ioStart Lab

✅ Phase 3 Checkpoint

You're ready for Phase 4 when you can:

  • Deploy a template with 5+ resources that depend on each other
  • Explain how Bicep resolves resource dependencies automatically
  • Deploy a VM you can actually SSH or RDP into
  • Identify when you do need an explicit dependsOn
Warning

VMs incur costs even when stopped (disk storage still charges). Always clean up after labs: az group delete --name rg-bicep-vm --yes --no-wait. Or better yet — learn deployment stacks in Phase 4, which handle cleanup for you.


📦 Phase 4: Deployment Stacks — Manage the Full Resource Lifecycle

⏱️ Time: 3–4 hours | 🎯 Goal: Control what happens to resources when your template changes

This is the phase most Bicep tutorials skip — and it's the one that matters most in production.

Here's the problem: you deploy 10 resources with Bicep. Next week, you remove 2 resources from your template and redeploy. What happens to those 2 resources? With a standard deployment — nothing. They stay in Azure, unmanaged, costing you money. They become drift.

Deployment stacks fix this.

What You'll Learn

ConceptWhy It Matters
Deployment stacksA management layer that tracks which resources belong to your template
actionOnUnmanageWhat happens when a resource is removed from the template — delete, detach, or deleteAll
denySettingsLock deployed resources to prevent manual portal changes (goodbye config drift)
Stack updatesUpdate your infrastructure safely by updating the stack, not just redeploying
Resource lifecycleThe full picture: create → update → remove → clean up

Why This Changes Everything

Without deployment stacks, Bicep is a deployment tool. With them, it's a management tool. Think of it like the difference between putting furniture in a room (deployment) vs. having an inventory system that knows what's there and removes what shouldn't be (stacks).

# Create a deployment stack
az stack group create \
  --name demo-stack \
  --resource-group rg-bicep-stacks \
  --template-file main.bicep \
  --action-on-unmanage deleteAll \
  --deny-settings-mode denyWriteAndDelete
 
# Now if you remove a resource from main.bicep and re-run...
# the stack DELETES the removed resource from Azure automatically

The --deny-settings-mode denyWriteAndDelete is the real power move — it prevents anyone from modifying or deleting your resources through the portal or CLI. Your Bicep template becomes the single source of truth.

🧪 Hands-On Lab

Lab: Bicep Deployment Stacks & Resource Lifecycle Management
Hands-on Lab

Lab: Bicep Deployment Stacks & Resource Lifecycle Management

Go beyond basic deployments. Learn how deployment stacks track, protect, and clean up your Azure resources — the feature that makes Bicep production-ready.

cloudlearn.ioStart Lab

✅ Phase 4 Checkpoint

You're ready for Phase 5 when you can:

  • Explain the difference between a standard deployment and a deployment stack
  • Create and update a deployment stack from the CLI
  • Configure actionOnUnmanage and explain what each option does
  • Apply deny settings to prevent manual changes to deployed resources

🎯 Phase 5: Conditions, Loops, and What-If — Production Patterns

⏱️ Time: 3–4 hours | 🎯 Goal: Write production-grade Bicep with conditional logic and safe deployment previews

This is where you go from "I can deploy things" to "I write infrastructure code that teams trust in production." Conditions let your templates adapt. Loops eliminate repetition. What-if lets you preview changes before they touch anything.

What You'll Learn

ConceptWhy It Matters
Conditional deploymentsDeploy resources only when certain criteria are met — skip dev-only or prod-only resources
Loops (for)Deploy multiple similar resources without copy-pasting resource blocks
What-if previewsSee exactly what will change BEFORE deploying — the safety net every team needs
Combining patternsReal templates use conditions + loops + parameters together

Conditions — Deploy Smarter, Not Harder

@allowed(['dev', 'staging', 'prod'])
param environment string
 
// Only deploy monitoring in staging and production
resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2023-09-01' = if (environment != 'dev') {
  name: 'log-${environment}'
  location: resourceGroup().location
  properties: {
    sku: {
      name: 'PerGB2018'
    }
    retentionInDays: environment == 'prod' ? 90 : 30
  }
}

One template. Three environments. The right resources in each — automatically.

Loops — Stop Repeating Yourself

param subnetNames array = ['web', 'app', 'data']
 
resource vnet 'Microsoft.Network/virtualNetworks@2023-11-01' = {
  name: 'vnet-main'
  location: resourceGroup().location
  properties: {
    addressSpace: { addressPrefixes: ['10.0.0.0/16'] }
    subnets: [for (name, i) in subnetNames: {
      name: 'snet-${name}'
      properties: {
        addressPrefix: '10.0.${i}.0/24'
      }
    }]
  }
}

Three subnets, zero duplication. Need six subnets next month? Update the array.

What-If — Preview Before You Break Things

az deployment group what-if \
  --resource-group rg-production \
  --template-file main.bicep \
  --parameters environment=prod
 
# Output shows:
# + Create: logAnalytics (new)
# ~ Modify: storageAccount (sku changed)
# - Delete: nothing

What-if is the command I run before every production deployment. It shows exactly what will be created, modified, or deleted — without touching anything. If the output looks wrong, you fix the template. If it looks right, you deploy with confidence.

🧪 Hands-On Lab

Lab: Bicep Conditions, Loops, and What-If Deployments
Hands-on Lab

Lab: Bicep Conditions, Loops, and What-If Deployments

Write production-grade templates with conditional logic, deploy resources in loops, and preview changes safely with what-if. The patterns that make teams trust your infrastructure code.

cloudlearn.ioStart Lab

✅ Phase 5 Checkpoint

You've completed the roadmap when you can:

  • Conditionally deploy resources based on environment parameters
  • Use for loops to deploy multiple resources from an array
  • Run what-if and correctly interpret the output
  • Explain why you'd use what-if in a CI/CD pipeline before az deployment group create

🗺️ The Complete Learning Path — At a Glance

PhaseYou LearnYou Can BuildLab
1. First TemplateResource declarations, deploy workflowA storage account via BicepStart
2. Expressions & ParamsParameters, variables, functions, outputsReusable multi-environment templatesStart
3. Real InfrastructureDependencies, networking, VMsA full VNet + VM stackStart
4. Deployment StacksLifecycle management, deny settingsSelf-cleaning, drift-protected infraStart
5. Production PatternsConditions, loops, what-ifSafe, adaptable production deploymentsStart

What's Next

After completing this roadmap, you're ready for:

  • Bicep modules — break large templates into reusable, versioned components
  • CI/CD pipelines — deploy Bicep through GitHub Actions or Azure DevOps with what-if gates
  • Bicep parameter files.bicepparam files for managing environment-specific values
  • Template specs — publish and share templates across teams and subscriptions

The engineers who ship reliable infrastructure aren't using different tools than you — they're using the same tools with more structure. This roadmap gave you that structure. Now go build.

CloudLearn — Hands-On Azure Labs
Hands-on LabCloudlearn - Hands-On AWS & Azure Training

CloudLearn — Hands-On Azure Labs

Every lab in this roadmap is available on CloudLearn. Guided, browser-based Azure labs — no setup, no credit card, just learn by doing.

cloudlearn.ioExplore All Labs

What's Next

Bookmark this page

Save it for your next project sprint

Start a project

Apply what you just learned hands-on

Follow on Instagram

Daily cloud tips & behind-the-scenes

Try hands-on labs

Practice in a real cloud environment

Parveen Singh

Parveen Singh

Microsoft Certified Trainer & Cloud Solutions Consultant

Related Field Notes

Found this useful?

Stay in the loop

Weekly cloud insights, no spam

Subscribe

Explore CloudLearn

Hands-on labs & projects

Start Learning

Book Training

Custom cloud training for your team

Get in Touch

On this page