top of page
  • Writer's pictureCloudlene Inc.

Bicep Overview

Updated: Oct 11, 2022

This article assumes that you are familiar – have heard of - with infrastructure as Code (IaC) technologies such as Terraform, Pulumi, ARM Templates for Azure, then you already understand where to use Bicep: To create Azure resources natively without having to muck with JSON.

[Aside for non-native English speakers: Your arm 🙋‍♂️ & bicep💪 , got it? 😁]

Here’s how easy bicep is to grok:

targetScope = 'resourceGroup/Subscription/Management Group/Tenant>' 
resource <symbolicName> ‘namespace provider@apiVersion’ = { 
  name: <the name you want to give your resource> 
  location: <where to deploy> 
targetScope = 'resourceGroup' 
resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-03-01' = { 
  location: 'eastus' 
  name: 'vm-poc-srv-dev-001' 

The above only requires you to know what resources that you want to deploy (A SQL database, an App Service or any of the hundreds of services that Azure supports), and the version number of the provider (usually, the latest). VSCode has great intellisense support.

What Do We Need? – Becoming a Newbie

Item Required

How to find

Provider Name

Versions Supported

  • List all providers with the version numbers they support

az provider list –query ‘[*].{namespace: namespace, apiVersion: resourceTypes[].apiVersions[]}’ 

The Latest Version

  • List all providers with their latest version numbers

az provider list --query '[*].{namespace: namespace, apiVersion: resourceTypes[].apiVersions[] | [0]}'  

Required Properties

  • VSCode has tooling support for adding required properties

resource storageAccount  'Microsoft.Storage/storageAccount@2022-05-01' = { }
  • Most of the providers have name, location as required properties

List of all Properties

What each property means

Azure Deployment Reference

What are the other resources this resource depends on?

  • Azure Portal UI – Manually Create the resource

  • Download the template

az bicep decompile -f template.json 
  • Bicep Quick Start Guide

How to find a quick snippet of working Bicep for the resource

  • Bicep Quick Start guide

  • VSCode Code Snippets

Execute the Bicep Script

az deployment group create -g <name> -l <location> -f poc.bicep

Execute the Bicep Script with Parameters

az deployment group create -g <name> -l <location> -f poc.bicep -p poc.parameters.json

Beyond ‘Hello World’ – Becoming an Intermediate

OK. You have everything you ever need and started writing bicep code. However, VS Code starts complaining that you’re hardcoding values and you need ‘Parameters’.

Parameters & default values

  • Parameters are declared using the param keyword

  • They are declared with a name, a datatype and an optional default value -- The parameters with no default values become required parameters

  • Do not default parameters except through a parameter file

Execute the Bicep Script passing parameters from an external parameters file

az deployment group create -g <name> -l <location> -f poc.bicep -p poc.parameters.json


  • Variables can be declared anywhere

  • They can hold value of all supported types (int, string, object, array)

  • Can be converted from one type to another where legal (For example, “555” can be converted to a number using int(“555”))

Functions that can only be used in parameter assignments

utcNow(), newGuid()

Reach for the Skies - Becoming Advance

Minimum functions you’d need

format(‘{0}-{1}-{2}’, var1, var2, var3) 

resource publicIpAddress 'Microsoft.Network/publicIPAddresses@2022-01-01' = if (attachPublicIP) { 
  name: 'pip-${nameSuffix}' 
  location: location 
  tags: coreTags 

param itemCount int = 5 
var stringArray = [for i in range(0, itemCount): 'item${(i + 1)}'] 
output arrayResult array = stringArray 


(isPublic)? <true expression>: <false expression>

Shoot for the moon – Becoming an Expert

Reuse Bicep files using Modules

module clientVM '' = { 
  name: 'windowsClientVM' 
  params: { 
    env: env 
    location: location 

Best Practices

While the base format of the language is very simple, using bicep emphasizing reuse, testability and modularity requires some thought and upfront planning.

Here’re the best practices I distilled, painstakingly assembled: 😉

  • A single or group (more typical) of bicep files are written for a “Project”

  • Follow the AZ naming convention from the CAF (for the most part except where the service barfs saying it can’t exceed ‘xx’ characters) for naming resources

  • Your entry point should always be main. Bicep

    • Makes it easy for someone to find the entry point quickly

  • Always assume your script would be used to create multiple environments

    • So, an execution always creates an environment for your project

  • Environments can be DEV, QA, INTG, STAGE, PROD or DEMO

    • It doesn’t matter what it’s called for the most part

    • Your scripts should never hard code any environment names except may be in the config files (which will be generated by the pipeline)

    • Always assume the default location where the Azure resources to be created will be dictated by the user

    • It may even change per environment

  • Follow lower case naming conventions for bicep

    • File name should be all lower case ending with the extension .bicep

    • Separate words with a hyphen: network-interface. Bicep

  • Typical parameters to consider for the main.bicep

    • env - The environment

    • projectName - The project this environment belongs to

    • location

    • coreTags

  • Parameters generally should not have default values

  • You should have a *.parameters.json for all your default parameters you want to debug the bicep file with

  • Every core azure service required must be in a separate file

    • network. Bicep

    • nsg.bicep

    • network-interface.bicep

  • Bicep files can refer / include other bicep files using 'modules' syntax

  • The overall structure of your bicep file should be:

    • Parameters

    • Variables

    • Global Config Module

    • Shared Modules

      • vnet

  • Every core azure service decled should belong to a component / service in your project

    • If you’re working to create

  • Create a nameSuffix & a nameSuffixShort

    • nameSuffixShort should denote items belonging at the project level (such as VNET). Example can be vnet-poc-dev-001

    • nameSuffix should include component. Example: plan-poc-wfe-dev-001

      • WFE == ‘Web Front End’

  • Always assume you’re just a node in the toolchain

    • Just because the pipeline supplied the password doesn’t mean the app might know it

    • Some output values generated by the core azure services such as the URL for an App Service etc. must be output as output variables

    • Put generated values that in a shared Key Vault

40 views0 comments

Recent Posts

See All


bottom of page