Azure Bicep: Infrastructure as Code Deep Dive

Azure Bicep is the next-generation language for Azure infrastructure as code, replacing ARM templates. With cleaner syntax, modules, and first-class tooling, Bicep significantly improves the IaC developer experience. This guide covers Bicep fundamentals, module patterns, deployment strategies, and migration from ARM templates.

Bicep vs ARM Templates

FeatureARM JSONBicep
SyntaxVerbose JSONClean DSL
Line Count100%~50%
ModulesLinked templatesNative modules
IntelliSenseLimitedFull VS Code support
CompilationSameCompiles to ARM

Basic Syntax

// Parameters with decorators
@description('The environment type')
@allowed(['dev', 'staging', 'prod'])
param environment string = 'dev'

@secure()
param adminPassword string

// Variables
var storageAccountName = 'st${uniqueString(resourceGroup().id)}'
var isProduction = environment == 'prod'

// Resources
resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
  name: storageAccountName
  location: resourceGroup().location
  sku: {
    name: isProduction ? 'Standard_GRS' : 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    minimumTlsVersion: 'TLS1_2'
    supportsHttpsTrafficOnly: true
  }
}

// Outputs
output storageEndpoint string = storageAccount.properties.primaryEndpoints.blob

Module Pattern

// modules/storage.bicep
param name string
param location string
param sku string = 'Standard_LRS'

resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
  name: name
  location: location
  sku: { name: sku }
  kind: 'StorageV2'
}

output connectionString string = 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value}'
// main.bicep
module storage 'modules/storage.bicep' = {
  name: 'storageDeployment'
  params: {
    name: 'stmyapp${environment}'
    location: resourceGroup().location
    sku: environment == 'prod' ? 'Standard_GRS' : 'Standard_LRS'
  }
}

// Reference module output
output storageConnection string = storage.outputs.connectionString

Deployment with What-If

# Preview changes (what-if)
az deployment group what-if \
  --resource-group my-rg \
  --template-file main.bicep \
  --parameters environment=prod

# Deploy
az deployment group create \
  --resource-group my-rg \
  --template-file main.bicep \
  --parameters environment=prod

Registry for Shared Modules

# Publish module to registry
az bicep publish \
  --file modules/storage.bicep \
  --target br:myregistry.azurecr.io/bicep/storage:v1.0
// Consume from registry
module storage 'br:myregistry.azurecr.io/bicep/storage:v1.0' = {
  name: 'storageDeployment'
  params: {
    name: 'stmyapp'
    location: resourceGroup().location
  }
}

Key Takeaways

  • Bicep compiles to ARM—same deployment engine
  • 50% less code than ARM JSON
  • Modules enable reusable infrastructure patterns
  • What-if preview prevents surprise changes
  • Private registry for enterprise module sharing

Discover more from C4: Container, Code, Cloud & Context

Subscribe to get the latest posts sent to your email.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.