Use when writing Azure Bicep templates for infrastructure deployment. Covers resource declarations, modules, parameters, outputs, and deployment commands. USE FOR: Azure resource deployment, Bicep DSL modules, what-if previews, Azure-native IaC DO NOT USE FOR: AWS resources (use cloud-formation), multi-cloud infrastructure (use terraform or pulumi), raw ARM JSON (use arm)
Resources
4Install
npx skillscat add tyler-r-kendrick/agent-skills/bicep Install via the SkillsCat registry.
SKILL.md
Azure Bicep
Overview
Bicep is Azure's domain-specific language for deploying Azure resources declaratively. It compiles to ARM JSON but provides a cleaner syntax with type safety, modules, and IDE support. Bicep is the recommended replacement for authoring ARM templates directly.
Basic Template
@description('The Azure region for all resources')
param location string = resourceGroup().location
@allowed(['dev', 'staging', 'prod'])
param environment string = 'dev'
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: 'st${uniqueString(resourceGroup().id)}${environment}'
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
minimumTlsVersion: 'TLS1_2'
supportsHttpsTrafficOnly: true
}
}
resource appServicePlan 'Microsoft.Web/serverfarms@2023-01-01' = {
name: 'asp-${environment}'
location: location
sku: {
name: environment == 'prod' ? 'P1v3' : 'B1'
}
}
resource webApp 'Microsoft.Web/sites@2023-01-01' = {
name: 'app-${environment}-${uniqueString(resourceGroup().id)}'
location: location
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
minTlsVersion: '1.2'
}
}
}
output webAppUrl string = 'https://${webApp.properties.defaultHostName}'
output storageAccountId string = storageAccount.idModules
Reusable components in separate .bicep files:
// modules/storage.bicep
param name string
param location string
param sku string = 'Standard_LRS'
resource storage 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: name
location: location
sku: { name: sku }
kind: 'StorageV2'
}
output id string = storage.id
output name string = storage.nameConsume in the main template:
module storage 'modules/storage.bicep' = {
name: 'storageDeployment'
params: {
name: 'stmyapp${environment}'
location: location
sku: environment == 'prod' ? 'Standard_GRS' : 'Standard_LRS'
}
}Deployment
# Deploy to a resource group
az deployment group create \
--resource-group my-rg \
--template-file main.bicep \
--parameters environment=prod
# What-if (preview changes)
az deployment group what-if \
--resource-group my-rg \
--template-file main.bicep
# Deploy to subscription scope
az deployment sub create \
--location eastus \
--template-file main.bicepKey Features
| Feature | Syntax |
|---|---|
| Parameters | param name string with decorators (@allowed, @minLength) |
| Variables | var name = expression |
| Resources | resource sym 'type@version' = { ... } |
| Modules | module sym 'path.bicep' = { params: {} } |
| Outputs | output name type = value |
| Loops | [for item in list: { ... }] |
| Conditions | if (condition) { ... } or ternary condition ? a : b |
| Existing resources | resource sym 'type@version' existing = { name: '...' } |
Best Practices
- Always use
what-ifto preview changes before deploying. - Use modules to break large templates into reusable, testable components.
- Use parameter decorators (
@allowed,@minLength,@description) for validation and documentation. - Reference existing resources with the
existingkeyword instead of hardcoding resource IDs. - Use
uniqueString(resourceGroup().id)for globally unique names (storage accounts, web apps). - Pin API versions on resources for predictable behavior.
- Use Bicep instead of ARM JSON — it compiles to identical output with better readability.