top of page

LetsDevOps: Azure Bicep-Modules, Best practice to create and use modules.


In this blog we will learn the bicep modules also we see the best practice on how to create and use bicep modules.

What is Bicep Modules

  • A module is a Bicep file (or an ARM JSON template) that is deployed from another Bicep file which helps to create resource in azure.

  • Modules are independent Bicep files.

  • Contain sets of resources that are deployed together.

  • Modules can be consumed from any other Bicep template.

Benefit of Bicep Modules

  1. Helps to split complex template in smaller parts.

  2. Focus on specific task.

  3. Resuable for multiple deployment.

  4. Easy to read and organize the deployment.

  5. Shareble to other team and organization.

Bicep Modules Syntax

module <symbolic-name> '<path-to-file>' = {
  name: '<linked-deployment-name>'
  params: {


  • A module can't have the same name as a parameter, variable, or resource.

  • The path can be either a local file or a file in a registry.

  • If a module with a static name is deployed concurrently to the same scope, there's the potential for one deployment to interfere with the output from the other deployment.

  • If you're concerned about concurrent deployments to the same scope, give your module a unique name.

How module works

It is not required to understand how module works but this will help to troubleshoot if any unexpetxed behaviour.

  • When you deploy a Bicep file by using the Azure CLI or Azure PowerShell, you can optionally specify the name of the deployment.

  • If no name given it pick the deployment name from the file name.

  • When you use modules, Bicep creates a separate deployment for every module.

  • When you deploy a Bicep file that contains a module, multiple deployment resources are created: one for the parent template and one for each module.

In this scenario if you run main bicep file 2 deployment will be created 1. main 2. myapp

Generated JSON ARM templates

When we deploy bicep file it get converted to jsom ARM template and that is called transpilation.

Parameters and Output in module

module parameters
  • It is best to use the parameters in the bicep but also advisable not to use the default value in module file.

  • Use the default value at parent bicep file.

appstorage.bicep [Module bicep]

@description('The name of the storage account to deploy.')
param storageAccountName string

main.bicep [Parent bicep]

@description('The name of the storage account to deploy.')
param storageAccountName string = 'srstestdemo'

Use conditions

We can add condition in module or any bicep file which gives us the flexibity to run/deploy the resource when there is certian condition met.

Example: Assume that I need to enable the diagnostic setting only when there is production run so with this we can set condition.

param logAnalyticsWorkspaceId string = ''

resource cosmosDBAccount 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' = {
  // ...
resource cosmosDBAccountDiagnostics 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' =  if (logAnalyticsWorkspaceId != '') {
  scope: cosmosDBAccount
  name: 'route-logs-to-log-analytics'
  properties: {
    workspaceId: logAnalyticsWorkspaceId
    logs: [
        category: 'DataPlaneRequests'
        enabled: true

Module outputs

Module can define outputs, it helps to use it in the parent bicep.

A parent template can use module outputs in variables, can use properties for other resource definitions, or can expose variables and properties as outputs itself.

@description('The fully qualified Azure resource ID of the blob container within the storage account.')

output blobContainerResourceId string =

Chain modules together

  • We can create a parent Bicep file that composes multiple modules together.

  • symbolic names are used for the reference between the modules

@description('Username for the virtual machine.')
param adminUsername string

@description('Password for the virtual machine.') 
param adminPassword string

module virtualNetwork 'modules/vnet.bicep' = {
    name: 'virtual-network' 

module virtualMachine 'modules/vm.bicep' = {   
    name: 'virtual-machine'
    params: {     
        adminUsername: adminUsername
        adminPassword: adminPassword
        subnetResourceId: virtualNetwork.outputs.subnetResourceId  


  1. Create main bicep file.

  2. Create module for an application.

  3. Add module to main bicep template.

  4. Create CDN module.

  5. Add CDN module to main bicep template.

Two Deployment created :


bottom of page