Insight Tech APAC Blog Logo

The Anatomy of a Bicep Template

stephentulp
December 5, 2023

6 minutes to read

Bicep Advent Calendar

Introduction

In this blog post, we will go over the various elements that make up a Bicep file, this will help understand the structure, syntax and properties of a Bicep template.

Bicep Template Elements

Bicep is a declarative language, which means the elements can appear in any order. Unlike imperative languages, the order of elements doesn’t affect how the deployment is processed.

A typical Bicep file has the following elements, User-Defined Data Types and User-Defined Functions have been excluded and we will address these later in the month.

metadata <metadata-name> = ANY

targetScope = '<scope>'

@<decorator>(<argument>)
param <parameter-name> <parameter-data-type> = <default-value>

var <variable-name> = <variable-value>

resource <resource-symbolic-name> '<resource-type>@<api-version>' = {
  <resource-properties>
}

module <module-symbolic-name> '<path-to-file>' = {
  name: '<linked-deployment-name>'
  params: {
    <parameter-names-and-values>
  }
}

output <output-name> <output-data-type> = <output-value>

Metadata

Metadata in Bicep is an untyped value that can be included in a Bicep file. It allows supplementary information about your Bicep files, including details like its name, description and author.

metadata name = 'Azure Landing Zone Vending Machine'
metadata description = 'Creates a repeatable and scalable Azure Landing Zone deployment using Bicep'
metadata author = 'Stephen Tulp - Insight'

Target scope

By default, the target scope is set to resourceGroup. If you’re deploying at the resource group level it is optional.

The allowed values are:

targetScope = 'managementGroup'

Parameters

Parameters are used for values that need to change and you can define a default value for the parameter that is used if no value is provided during deployment.

For example, virtualNetworkEnabled default value is set to true but could be overwritten in a template parameter file, while envPrefix will be required in a template parameter file.

param virtualNetworkEnabled bool = true
param envPrefix string

Parameter decorators

You can add one or more decorators for each parameter. These decorators describe the parameter and define constraints for the values that are passed in. The following example shows one decorator for envPrefix and we have updated it to use a default value.

@allowed([
  'dev'
  'test'
  'prod'
])
param envPrefix string = 'dev'

Variables

You can make your Bicep file more readable by encapsulating complex expressions in a variable. This is used for concatenating names of resources and resource groups for example.

var resourceGroups = {
  network: '${argPrefix}-network'
  shared: '${argPrefix}-shared'
}

Apply this variable wherever you need the complex expression.

resource resourceGroupNetwork 'Microsoft.Resources/resourceGroups@2021-04-01' = {
  name: resourceGroups.network
}

resource resourceGroupShared 'Microsoft.Resources/resourceGroups@2021-04-01' = {
  name: resourceGroups.shared
}

Resources

Use the resource keyword to define a resource to deploy, this includes a symbolic name for the resource. The symbolic name can be used in other parts of the Bicep file to get a value from the resource.

The resource declaration includes the resource type and API version within the body of the resource declaration and includes properties that are specific to the resource type.

resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
  name: resourceGroupName
  location: location
  tags: tags
}

Modules

Modules enable the reuse code from a Bicep file in other Bicep files. In the module declaration, you link to the file to reuse. When you deploy the Bicep file, the resources in the module are also deployed.

module resourceGroup '../resourceGroup/resourceGroup.bicep' = {
  name: 'resourceGroup-${guid(deployment().name)}'
  scope: subscription(subscriptionId)
  params: {
    resourceGroupName: resourceGroups.network
    location: location
    tags: tags
  }
}

Outputs

Use outputs to return values from the deployment. Typically, you return a value from a deployed resource when you need to reuse that value for another operation.

output resourceGroupShared string = resourceGroupShared.name
output resourceGroupNetwork string = resourceGroupNetwork.name

Comments

Use // for single-line comments or /* ... */ for multi-line comments

The following example shows a single-line comment.

// Resource: Resource Group
resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
  ...
}

Conclusion

The following example shows an implementation of all these elements outlined above. Later in the month, we will go into more detail to include other pieces that will make up the Landing Zone.

metadata name = 'Resource Group Bicep Template'
metadata description = 'Resource Group Example'
metadata author = 'Stephen Tulp - Insight'

targetScope = 'subscription'

@description('The Azure Region to deploy the resources into.')
param location string = deployment().location

@description('An object of Tag key & value pairs to be appended to a Subscription.')
param tags object = {
  applicationName: 'SAP Landing Zone'
  owner: 'Platform Team'
  criticality: 'Tier1'
  costCenter: '1234'
  contactEmail: 'test@test.com'
  dataClassification: 'Internal'
}

var resourceGroups = {
  network: 'arg-syd-sap-prd-network'
  shared: 'arg-syd-sap-prd-shared'
}

// Module: Resource Group (Shared)
module resourceGroupShared 'resource-group/main.bicep' = {
  name: 'resourceGroupShared-${guid(deployment().name)}'
  params: {
    name: resourceGroups.shared
    location: location
    tags: tags
  }
}

// Resource: Resource Group (Network)
resource resourceGroupNetwork 'Microsoft.Resources/resourceGroups@2021-04-01' = {
  name: resourceGroups.network
  location: location
  tags: tags
}

output resourceGroupShared string = resourceGroupShared.name
output resourceGroupNetwork string = resourceGroupNetwork.name

The above example is available in the Insight Bicep Advent Calendar GitHub Repository

Further Reading

Some further reading on the topics covered in this post: