Azure Bicep Naming Conventions: CAF Compliant Resource Names
How to generate and enforce CAF compliant Azure resource names in Bicep templates, including the azure-naming module, string functions, and practical examples.
In Bicep, compose names with string interpolation, for example
var kvName = 'kv-${workload}-${environment}-${region}-${instance}', and usetake()to enforce length limits. For production templates, the communityavm/utl/namingmodule applies each resource type’s rules for you.
If you’re writing Bicep templates, naming resources consistently is one of the first design decisions you’ll make, and one of the hardest to change later. This guide covers how to apply Microsoft’s Cloud Adoption Framework (CAF) naming conventions in Bicep, from simple string construction to reusable naming modules.
The CAF naming pattern
Microsoft’s CAF defines a standard component order:
{type}-{company}-{department}-{workload}-{environment}-{region}-{instance}
Not every resource uses every component. In practice, most teams use a simplified pattern:
{type}-{workload}-{environment}-{region}-{instance}
Examples:
| Resource | Type prefix | Example name |
|---|---|---|
| Virtual machine | vm | vm-payments-prod-eus-001 |
| Key Vault | kv | kv-payments-prod-eus-001 |
| Storage account | st | stpaymentsprodeus001 |
| App Service | app | app-payments-prod-eus-001 |
| Container Registry | cr | crpaymentsprodeus001 |
Building names in Bicep
Bicep gives you string interpolation and functions to compose names dynamically. Here’s a straightforward approach:
param workload string = 'payments'
param environment string = 'prod'
param region string = 'eus'
param instance string = '001'
var kvName = 'kv-${workload}-${environment}-${region}-${instance}'
var stName = 'st${workload}${environment}${region}${instance}'
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
name: kvName
location: resourceGroup().location
properties: {
sku: {
family: 'A'
name: 'standard'
}
tenantId: subscription().tenantId
}
}
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: stName
location: resourceGroup().location
kind: 'StorageV2'
sku: {
name: 'Standard_LRS'
}
}
Note that storage accounts only allow lowercase alphanumeric characters, no hyphens. The variable definition reflects this.
Using the azure-naming Bicep module
The community azure-naming Bicep module handles resource-specific constraints automatically, max lengths, allowed characters, and separator rules per resource type.
module naming 'br/public:avm/utl/naming/azure:0.1.0' = {
name: 'naming'
params: {
suffix: [workload, environment, region, instance]
}
}
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
name: naming.outputs.keyVaultName
location: resourceGroup().location
properties: {
sku: { family: 'A', name: 'standard' }
tenantId: subscription().tenantId
}
}
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: naming.outputs.storageAccountName
location: resourceGroup().location
kind: 'StorageV2'
sku: { name: 'Standard_LRS' }
}
This is the recommended approach for production templates, the module enforces length limits and character restrictions per resource type so you don’t have to manage them manually.
A reusable naming module (no external dependencies)
If you prefer not to use the public registry, here’s a lightweight naming module you can include directly in your repo:
// modules/naming.bicep
param workload string
param environment string
param region string
param instance string = '001'
var base = '${workload}-${environment}-${region}-${instance}'
var baseNoHyphen = toLower(replace(replace(base, '-', ''), '_', ''))
output keyVault string = take('kv-${base}', 24)
output storageAccount string = take('st${baseNoHyphen}', 24)
output appService string = take('app-${base}', 60)
output containerRegistry string = take('cr${baseNoHyphen}', 50)
output resourceGroup string = 'rg-${base}'
output virtualNetwork string = take('vnet-${base}', 64)
output keyVaultPrivateEndpoint string = take('pe-kv-${base}', 64)
Call it from your main template:
module names 'modules/naming.bicep' = {
name: 'naming'
params: {
workload: 'payments'
environment: 'prod'
region: 'eus'
instance: '001'
}
}
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
name: names.outputs.keyVault
// resolves to: kv-payments-prod-eus-001
location: resourceGroup().location
properties: {
sku: { family: 'A', name: 'standard' }
tenantId: subscription().tenantId
}
}
Environment and region abbreviations
Use consistent short codes across all templates:
Environments:
| Environment | Abbreviation |
|---|---|
| Production | prod |
| Staging | stg |
| Development | dev |
| Testing | tst |
| UAT | uat |
Regions (community convention):
| Region | Abbreviation |
|---|---|
| East US | eus |
| East US 2 | eus2 |
| West US 2 | wus2 |
| West Europe | weu |
| North Europe | neu |
| UK South | uks |
| Southeast Asia | sea |
| Australia East | aue |
Key naming constraints
Different resource types have very different constraints. These are the ones most likely to trip you up:
| Resource | Max length | Allowed characters | Hyphens allowed |
|---|---|---|---|
| Storage account | 24 | Lowercase alphanumeric | No |
| Key Vault | 24 | Alphanumeric and hyphens | Yes |
| Container Registry | 50 | Alphanumeric | No |
| Virtual machine | 64 | Alphanumeric and hyphens | Yes |
| App Service | 60 | Alphanumeric and hyphens | Yes |
| Resource group | 90 | Alphanumeric, hyphens, underscores, periods | Yes |
Note that the Windows computer name (the OS host name) is capped at 15 characters and is set separately from the 64-character VM resource name, see the VM naming guide.
AzureNamer exports ready-to-paste Bicep for all 200+ Azure resource types, either exact names or a parameterized, variable-driven file, free, no login required.
Summary
- Use string interpolation for simple templates; the
azure-namingmodule for production - Store naming parameters (
workload,environment,region) in a params file, never hardcode them - Watch out for storage accounts and container registries: no hyphens, lowercase only, short max length
- Standardize names from day one, retrofitting them onto existing resources is painful
Keep reading
Naming Azure Resources in Terraform: A CAF Compliant Approach
How to implement Microsoft CAF naming conventions in Terraform using locals, including handling Storage Accounts, Key Vaults, and other resources with tight character limits.
Read →Azure API Management Naming Conventions: Service, APIs, and Products
CAF naming for Azure API Management. The service is a globally unique azure-api.net endpoint (1 to 50 chars); APIs, products, backends, and named values inside are function-named. Patterns and examples.
Read →Azure Service Bus Naming Conventions: Namespaces, Queues, and Topics
CAF naming for Azure Service Bus. The namespace is a globally unique servicebus.windows.net endpoint (6 to 50 chars); queues, topics, and subscriptions inside are relaxed. Patterns and examples.
Read →Try AzureNamer
Generate CAF compliant names for all 200+ Azure resource types, free, no login required.
Open the Generator →