What’s New in Bicep 0.40.2

What’s New in Bicep 0.40.2

Introduction

Bicep 0.40.2 was released at the end of January and covered in the Community call (hopefully available on YouTube soon). This release graduates several experimental features to GA while introducing new capabilities for template authoring and automation. The focus is on improving string handling, enabling conditional resource configuration, and strengthening AI integration through Model Context Protocol support.

I have been using Bicep on a number of projects recently, and this release helps address a few issues I have encountered.

Multi-line Interpolated Strings now Generally Available

Multi-line interpolated strings have graduated to general availability in 0.40.2. This feature finally makes it practical to embed complex scripts, JSON configurations, and formatted text directly in Bicep templates without wrestling with concatenation or escape sequences.

JSON Configuration Embedding

I recently encountered this scenario with Azure Policy Definitions. Rather than converting the entire policyRule into a Bicep parameter, I can now embed JSON directly while keeping it modifiable.

param policyEffect = 'deny'
param policyRule = $'''
{
  "if": {
    "field": "[concat('tags[', parameters('tagName'), ']')]",
    "exists": "false"
  },
  "then": {
    "effect": "${policyEffect}"
  }
}
'''

Escaping Interpolation

When you need literal ${} syntax (like in shell scripts or Kubernetes manifests), use multiple $ characters. The escaping rule is simpler than it sounds. If you start with $$''', you need $${} to interpolate Bicep variables. Single ${} stays literal.

var namespace = 'production'
var scriptWithLiterals = $$'''
#!/bin/bash
# These are literal - not interpolated:
export CONFIG_PATH=${HOME}/.config
export LITERAL_VAR=${SOME_VAR}

# This IS interpolated (two dollar signs):
export NAMESPACE=$${namespace}
'''

In this example:

  • $$''' starts the string with one level of escaping
  • ${HOME} and ${SOME_VAR} stay literal
  • $${namespace} interpolates to 'production'

Resource Existence Checks (Experimental)

The Bicep team also announced the new experimental feature of this.exists() and this.existingResource(). I have yet to play with this in anger but my understanding is that these functions work at the resource level (like onlyIfNotExists() ). They cannot be used at the module level. The functions allow you to perform a boolean check for whether the resource has already been deployed using this.exists() and then pull pre-existing resource configuration via the this.existingResource() reference.

The this.exists() function returns a boolean indicating whether the current resource exists in Azure:

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: 'mystorageacct001'
  location: 'eastus'
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    // Apply different settings based on whether resource exists
    publicNetworkAccess: this.exists() ? 'Enabled' : 'Disabled'
    
    // Use secure default for new deployments
    minimumTlsVersion: this.exists() ? 'TLS1_2' : 'TLS1_2'
  }
}

This example shows conditional logic based on resource existence. For more complex scenarios where you need to read existing resource properties, use this.existingResource() function separately.

Important: This feature is experimental in 0.40.2. You need to enable it in bicepconfig.json:

{
  "experimentalFeaturesEnabled": {
    "resourceExistenceChecks": true
  }
}

Model Context Protocol (MCP) Server Tools

Bicep 0.40.2 introduces six MCP server tools that enable AI assistants and automation systems to interact with Bicep templates programmatically.

I have been looking at the Model Context Protocol recently. It is an open standard that connects AI systems to data sources and tools. Bicep’s MCP server exposes six tools that AI agents can invoke to analyze, transform, and work with Bicep templates.

The Six MCP Tools

  1. decompile_arm_parameters_file - Converts ARM JSON parameter files to .bicepparam format
  2. decompile_arm_template_file - Transforms ARM JSON templates to Bicep syntax
  3. format_bicep_file - Applies consistent formatting to Bicep files
  4. get_bicep_file_diagnostics - Returns compilation errors, warnings, and linting results
  5. get_file_references - Lists all modules, parameters, and dependencies
  6. get_deployment_snapshot - Creates deployment previews from parameter files

Bicep Console Enhancements

The bicep console command, introduced in earlier versions for interactive expression evaluation, now supports piping and stdin/stdout redirection. This seemingly small change enables powerful automation scenarios.

The Console Command

Bicep console lets you evaluate expressions without deploying templates:

bicep console
> parseCidr('172.18.0.0/20')
{
  network: '172.18.0.0'
  netmask: '255.255.240.0'
  broadcast: '172.18.15.255'
  firstUsable: '172.18.0.1'
  lastUsable: '172.18.15.254'
  cidr: 20
}

New: Piping Support

With 0.40.2, you can pipe expressions directly:

echo "parseCidr('172.18.0.0/20')" | bicep console

This returns the evaluation result as JSON output, which is perfect for scripts and automation workflows.

Conclusion

0.40.2 brings an interesting update to multi-line interpolation that I am hoping to get into production projects soon, and the experimental features are something I will need to test more fully to get a better understanding. I hope these will help with some edge cases within project repos that need this kind of existence check.

I need to spend some time with the new MCP tools to see how useful they are for my workflows. Alongside the console changes, I hope this will help with validation and testing, especially when using GitHub Copilot or other AI agents.

Further Reading