Getting Started with Bicep
What Is Bicep?
Bicep is a domain-specific language (DSL) for deploying Azure resources declaratively. It transpiles to ARM JSON templates but offers a much cleaner, more readable syntax.
Why Bicep over ARM Templates?
ARM JSON
Traditional Azure Resource Manager templates
SyntaxVerbose JSON
ModulesLinked/nested templates
Type safetyLimited
ReadabilityPoor for complex templates
ToolingVS Code extension
Bicep
Clean, concise domain-specific language
SyntaxClean, concise DSL
ModulesFirst-class module support
Type safetyFull IntelliSense and validation
ReadabilityExcellent
ToolingVS Code extension with rich features
Your First Bicep File
Create a file called main.bicep:
@description('The Azure region for resources')
param location string = resourceGroup().location
@description('Environment name')
@allowed([
'dev'
'test'
'prod'
])
param environment string = 'dev'
var storageName = 'st${uniqueString(resourceGroup().id)}${environment}'
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: storageName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
minimumTlsVersion: 'TLS1_2'
supportsHttpsTrafficOnly: true
}
}
output storageAccountId string = storageAccount.id
output storageAccountName string = storageAccount.name
Deploying
# Create a resource group
az group create --name rg-demo --location uksouth
# Deploy the Bicep file
az deployment group create \
--resource-group rg-demo \
--template-file main.bicep \
--parameters environment=dev
Parameters
Parameters accept input values at deployment time:
param appName string
param location string = resourceGroup().location
@minValue(1)
@maxValue(10)
param instanceCount int = 1
@secure()
param adminPassword string
Use a parameter file for environment-specific values:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appName": { "value": "myapp" },
"instanceCount": { "value": 3 }
}
}
Modules
Break large deployments into reusable modules:
module vnet './modules/vnet.bicep' = {
name: 'vnet-deployment'
params: {
location: location
vnetName: 'vnet-${environment}'
addressPrefix: '10.0.0.0/16'
}
}
// Reference module outputs
output vnetId string = vnet.outputs.vnetId
Best Practices
- Use parameter decorators (
@description,@allowed,@minValue) for documentation and validation - Organise with modules — one module per logical resource group
- Use
existingkeyword to reference resources deployed elsewhere - Store modules in a Bicep Registry for cross-team reuse
- Always set
minimumTlsVersionand other security properties