Bicep Expressions and Functions

Expressions and functions add intelligence to Bicep templates. Instead of hardcoding values, expressions calculate them dynamically. Bicep provides dozens of built-in functions that generate unique names, retrieve resource metadata, manipulate strings, perform math, and work with arrays and objects. Mastering these functions makes templates flexible and production-ready.

What Is an Expression in Bicep?

An expression is any value that Bicep evaluates at deployment time. Expressions go wherever a value is expected — inside parameters, variables, resource properties, and outputs.

// Simple literal (not an expression)
param location string = 'eastus'

// Expression using a function
var uniqueSuffix = uniqueString(resourceGroup().id)

// Expression using string interpolation
var storageName = 'st${uniqueSuffix}'

// Expression using a ternary operator
var sku = environment == 'prod' ? 'Standard_GRS' : 'Standard_LRS'

Categories of Bicep Functions

+----------------------------------------------------------+
|               Bicep Function Categories                  |
+------------------+---------------------------------------+
|  Category        |  Purpose                              |
+------------------+---------------------------------------+
|  String          |  Manipulate and format text           |
|  Numeric         |  Math operations                      |
|  Array           |  Work with lists                      |
|  Object          |  Work with key-value pairs            |
|  Resource        |  Get resource metadata                |
|  Deployment      |  Get deployment context               |
|  Date/Time       |  Work with timestamps                 |
|  Logical         |  Conditional logic                    |
+------------------+---------------------------------------+

String Functions

concat() – Joins strings together

var appName = 'webapp'
var env = 'prod'

// concat() joins multiple strings
var fullName = concat(appName, '-', env)     // 'webapp-prod'

// String interpolation is cleaner (preferred)
var fullNameAlt = '${appName}-${env}'        // 'webapp-prod'

toLower() and toUpper() – Change letter case

param environment string = 'PRODUCTION'

// Normalize to lowercase for resource naming
var envLower = toLower(environment)     // 'production'
var envUpper = toUpper(environment)     // 'PRODUCTION'

replace() – Swap part of a string

var name = 'my-app-name'

// Storage accounts cannot contain hyphens – replace them
var storageName = replace(name, '-', '')    // 'myappname'

substring() – Extract part of a string

var fullText = 'productionEnvironment'

// Get characters starting at position 0, taking 4 characters
var short = substring(fullText, 0, 4)   // 'prod'

take() – Get first N characters

var longName = 'developmentenvironment'

// Take first 8 characters
var shortName = take(longName, 8)    // 'developm'

contains() – Check if a string has a value

var resourceName = 'prod-webapp-eastus'

// Returns true if the string contains 'prod'
var isProd = contains(resourceName, 'prod')    // true

trim() – Remove leading and trailing spaces

var rawInput = '  eastus  '
var cleanInput = trim(rawInput)    // 'eastus'

uniqueString() – Generating Unique Resource Names

This is one of the most used functions in Bicep. It generates a deterministic 13-character hash from input values. Deterministic means the same input always produces the same output — so re-deploying creates no duplicates.

// Always produces the same result for the same resource group
var suffix = uniqueString(resourceGroup().id)

// Combine with a prefix for a readable unique name
var storageAccountName = 'st${suffix}'

// Combine multiple seeds for more uniqueness
var uniqueName = uniqueString(resourceGroup().id, deployment().name)
How uniqueString Works

Input: resourceGroup().id
= '/subscriptions/aaaa/resourceGroups/myRG'
         │
         ▼
    [Hash Algorithm]
         │
         ▼
Output: 'xkpq4r7nm2abc'   (always the same for same input)
         │
         ▼
Prefix + Output = 'stxkpq4r7nm2abc'

Resource Functions

resourceGroup() – Get the current resource group details

// Get the resource group ID
var rgId = resourceGroup().id

// Get the resource group name
var rgName = resourceGroup().name

// Get the resource group location
var rgLocation = resourceGroup().location

// Use the resource group location for all resources
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: 'mystorage001'
  location: resourceGroup().location    // inherit from resource group
  sku: { name: 'Standard_LRS' }
  kind: 'StorageV2'
}

subscription() – Get the current subscription details

var subId = subscription().subscriptionId
var subName = subscription().displayName
var tenantId = subscription().tenantId

deployment() – Get the current deployment details

var deploymentName = deployment().name
var deploymentLocation = deployment().location

Numeric Functions

// min() – returns the smallest number
var smallerValue = min(5, 10)         // 5
var smallestInArray = min([3, 7, 1])  // 1

// max() – returns the largest number
var largerValue = max(5, 10)          // 10

// add, sub, mul, div, mod
var sum = 5 + 3        // 8
var difference = 10 - 4  // 6
var product = 3 * 4    // 12
var quotient = 10 / 2  // 5
var remainder = 10 % 3 // 1

Array Functions

length() – Count items in an array

var regions = ['eastus', 'westus', 'centralus']
var regionCount = length(regions)    // 3

union() – Merge two arrays or objects

var baseTags = {
  environment: 'prod'
  managedBy: 'Bicep'
}

var extraTags = {
  project: 'ecommerce'
}

// Combine both tag objects
var allTags = union(baseTags, extraTags)
// Result: { environment: 'prod', managedBy: 'Bicep', project: 'ecommerce' }

contains() – Check if array has a value

var allowedRegions = ['eastus', 'westus']
var isAllowed = contains(allowedRegions, 'eastus')    // true

first() and last() – Get first or last item

var names = ['alpha', 'beta', 'gamma']
var firstItem = first(names)    // 'alpha'
var lastItem = last(names)      // 'gamma'

Logical Functions

if() – Return one value or another based on a condition

param environment string = 'prod'

// if(condition, trueValue, falseValue)
var instanceCount = if(environment == 'prod', 3, 1)

// Ternary operator does the same (preferred syntax)
var instanceCountAlt = environment == 'prod' ? 3 : 1

and(), or(), not()

param environment string = 'prod'
param region string = 'eastus'

var isHighAvailability = and(environment == 'prod', region == 'eastus')
// true only when BOTH conditions are true

var useRedundancy = or(environment == 'prod', environment == 'staging')
// true when EITHER condition is true

var isNotProd = not(environment == 'prod')
// true when condition is false

The Ternary Operator – Conditional Expressions

The ternary operator is the most common expression in real Bicep templates. It chooses between two values based on a condition.

Syntax: condition ? valueWhenTrue : valueWhenFalse

+-------------------+
|   condition?      |
+-------------------+
       │
   ┌───┴───┐
  true    false
   │       │
   ▼       ▼
value1   value2
param environment string = 'prod'

// Storage redundancy based on environment
var storageSku = environment == 'prod' ? 'Standard_GRS' : 'Standard_LRS'

// App Service tier based on environment
var appTier = environment == 'prod' ? 'P1v3' : 'B1'

// Enable backups only in production
var backupEnabled = environment == 'prod' ? true : false

// Set replica count
var replicas = environment == 'prod' ? 3 : 1

Complete Example – Functions in a Real Template

param environment string = 'prod'
param appName string = 'orderservice'
param location string = resourceGroup().location

// Build consistent names using string functions
var cleanAppName = toLower(replace(appName, ' ', ''))
var uniqueSuffix = take(uniqueString(resourceGroup().id), 6)
var storageAccountName = 'st${cleanAppName}${uniqueSuffix}'
var webAppName = 'app-${cleanAppName}-${environment}'

// Conditional settings based on environment
var storageSku = environment == 'prod' ? 'Standard_GRS' : 'Standard_LRS'
var appServiceSku = environment == 'prod' ? 'P1v3' : 'B1'
var httpsOnly = environment == 'prod' ? true : false

// Tags using union to combine base and extra tags
var baseTags = {
  managedBy: 'Bicep'
  environment: environment
}
var appTags = union(baseTags, {
  application: appName
  costCenter: 'IT-${toUpper(environment)}'
})

// Resources
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: storageAccountName
  location: location
  tags: appTags
  sku: {
    name: storageSku
  }
  kind: 'StorageV2'
  properties: {
    supportsHttpsTrafficOnly: httpsOnly
  }
}

resource appServicePlan 'Microsoft.Web/serverfarms@2023-01-01' = {
  name: 'asp-${cleanAppName}-${environment}'
  location: location
  tags: appTags
  sku: {
    name: appServiceSku
  }
}

// Outputs using functions
output storageAccountName string = storageAccount.name
output webAppUrl string = 'https://${webAppName}.azurewebsites.net'
output deployedRegion string = toUpper(location)

Quick Function Reference

FunctionExampleResult
uniqueString()uniqueString(resourceGroup().id)'xkpq4r7nm2abc'
toLower()toLower('PROD')'prod'
toUpper()toUpper('prod')'PROD'
replace()replace('my-app', '-', '')'myapp'
take()take('production', 4)'prod'
length()length(['a','b','c'])3
contains()contains('prod-app', 'prod')true
concat()concat('app', '-', 'prod')'app-prod'
union()union({a:1}, {b:2}){a:1, b:2}
resourceGroup()resourceGroup().location'eastus'
subscription()subscription().subscriptionId'aaaa-bbbb-...'
min()min(3, 7)3
max()max(3, 7)7

Summary

Bicep expressions and built-in functions turn static templates into dynamic, intelligent infrastructure code. String functions format and clean names. The uniqueString() function generates stable unique suffixes. Resource functions like resourceGroup() and subscription() retrieve deployment context. The ternary operator enables environment-aware configurations. Combining these tools results in templates that adapt automatically to different environments and requirements.

Leave a Comment