Import and Export feature across Bicep Templates
Stephen Tulp
December 22, 2023
3 minutes to read
Introduction
One of the guiding principles of software development is adopting the “Don’t repeat yourself” (DRY) approach to writing IaC which aims to reduce repetition of code by replacing it with abstractions. The export()
and import
capabilities in Bicep are experimental features that can help us achieve this goal.
The @export()
decorator is used to indicate that a given value can be imported by another file across type
, variable
and function
statements, while the import
statement enables the exported values to be used across multiple Bicep templates.
The @export()
decorator syntax is outlined below.
@export()
<statement_to_export>
Then we have a couple of ways that we can import these into other Bicep templates.
- Import functionality to another Bicep file
import {<symbol_name>, <symbol_name>, ...} from '<bicep_file_name>'
- Import using an alias to rename the symbol
import {<symbol_name> as <alias_name>, ...} from '<bicep_file_name>'
- Using a wildcard to import all exported values
import * as <alias_name> from '<bicep_file_name>'
Bicep CLI version 0.23.X or higher is required to use the Import/Export features and the experimental feature compileTimeImports
must be enabled from the Bicep config file.
Example Use Case
Lets have a look at an example where we will use both the export()
and import
feature across some Azure Landing Zone templates.
Export
A Bicep templates called shared.bicep
is used that has the exported values defined as locPrefixes
, tagsType
, commonResourceGroups
and namePrefixes
, these values can now be imported into other Bicep templates.
@export()
var locPrefixes = {
australiaEast: 'syd'
}
@export()
type tagsType = {
environment: 'Platform Production' | 'prd' | 'dev' | 'test'
applicationName: string
owner: string
criticality: 'Tier0' | 'Tier1' | 'Tier2' | 'Tier3'
costCenter: string
contactEmail: string
dataClassification: 'Internal' | 'Confidential' | 'Secret' | 'Top Secret'
iac: 'Bicep'
*: string
}
@export()
var commonResourceGroups = ['ascExportRG', 'alertsRG', 'networkWatcherRG']
@export()
var namePrefixes = {
platform: 'plat'
platformIdam: 'idam'
resourceGroup: 'arg'
keyVault: 'akv'
}
@export()
var identityPrefixes = {
argPrefix: toLower('${namePrefixes.resourceGroup}-${locPrefixes.australiaEast}-${namePrefixes.platform}-${namePrefixes.platformIdam}')
akvPrefix: toLower('${namePrefixes.keyVault}${locPrefixes.australiaEast}${namePrefixes.platformIdam}')
}
Import
We can now import these values into the platformIdentity.bicep
template, I have only included parts of the template relevant. We are using an alias for identityPrefixes as prefixes to help build out names for resources.
import { identityPrefixes as prefixes , tagsType, commonResourceGroups } from '../../configuration/shared/shared.bicep'
@description('The Azure Region to deploy the resources into.')
param location string = deployment().location
@description('Tags that will be applied to all resources in this module.')
param tags tagsType
var maxNameLength = 24
var uniquenameUntrim = '${prefixes.akvPrefix}${uniqueString(subscriptionId)}'
var resourceGroups = {
security: '${prefixes.argPrefix}-security'
}
var resourceNames = {
keyVault: (length(uniquenameUntrim) > maxNameLength ? substring(uniquenameUntrim, 0, maxNameLength) : uniquenameUntrim)
}
// Module: Resource Groups (Common)
module sharedResourceGroups '../../modules/resourceGroup/resourceGroups.bicep' = [for item in commonResourceGroups: {
name: item
scope: subscription(subscriptionId)
params: {
resourceGroupNames: commonResourceGroups
location: location
tags: tags
}
}]
Conclusion
The Import and Export decorators in Bicep are a powerful feature that allows for greater modularity and reusability in your Bicep templates. By understanding and utilizing this feature, you can create more efficient and maintainable Bicep templates and remove the need to repeat values across templates.