Azure Bicep Understanding Export and Import Attributes for Reusability

In this article, we are going to learn about the new feature of bicep called export and import attributes. Using this feature, we can reuse variables, types, and functions.

Let's get started learning about import and export attributes, and their advantages with examples.

Overview

With the introduction of @export() and import attributes, Bicep has taken a significant step towards enabling reusability and modular design in infrastructure templates.

These features allow developers to define shared components, types, and variables in one file and reuse them across multiple Bicep files, making IaC projects more organized, maintainable, and scalable.

This article will dive into the @export() and import attributes, their syntax, use cases, benefits, and limitations, alongside practical examples.

Concepts

What is @export()?

The @export() attribute allows you to expose variables, user-defined types, and user-defined functions from a Bicep file. These elements can then be consumed in other files through the import statement (@ is not required for this), making shared components reusable.

What is import?

The import attribute is used to consume elements marked with @export() in another Bicep file. It allows for explicit references to shared components, avoiding redundancy in code.

Advantages

  1. Code Reusability: Centralize shared components like variable definitions, types, or functions, reducing duplication.
  2. Improved Maintainability: Changes in one place automatically reflect in all dependent files.
  3. Scalability: Simplifies managing large infrastructure codebases by creating logical separations.
  4. Reduced Complexity: Explicit dependencies make it easier to understand the relationships between components.

In the rest of this article, we are going to learn.

  1. Re-use the Bicep Variables declared in a file called constants.bicep
  2. Re-use the Bicep Functions declared in a file called common-functions.bicep

Let’s get started by creating these two files and adding the code.

  1. Constants.bicep: contains all the common variables, and types that need to be re-used across all the other bicep files.
  2. Common-functions.bicep: contains all the functions that need to be re-used across all other bicep files.

Use Case 1: Re-using Primitive Literals

Let’s now define the constants that you may need in a file called Constants.bicep as shown below. Please note each variable that you want to re-use must be decorated by using @export() explicitly as shown below.

Constants.bicep

@export()
var CostCenter = 'HR1234'

@export()
var Project = 'BicepProject'

main.bicep

Let’s now see how to import all the variables in another bicep as shown below.

import * as Constants from 'constants.bicep'

In the above example, an asterisk (*) is used to import all the variables that are exported. Please note that you have to export the constants. bicep file in all the bicep files where you would like to refer the constants.

Once you import the constants, you can access the individual constants using the below syntax.

Output

Use Case 2: Re-using Types

What are Types?

Bicep supports defining custom types using the type keyword, allowing you to encapsulate multiple primitive types to align with the domain model. Below are examples.

  1. Bicep requires you to provide specific properties for each Azure resource you intend to create. For each resource type, it can be beneficial to define a custom type to streamline your configurations.
  2. In your project, you might need to establish a domain model for each microservice or domain. This allows you to define and manage distinct properties tailored to the specific requirements of each domain or service.

Let’s now learn more about re-using the types with code examples as shown below.

Again, in the constants.bicep, create a new type with all the properties required for creating the Storage Account as shown below.

@export()
type storageAccountType = {
  name: string
  location: string
  kind: string
  sku: {
    name: string
  }
  properties: {
    accessTier: string
    isHnsEnabled: bool
    allowBlobPublicAccess: bool
  }
}

In the main.bicep file, or any other Bicep file where you intend to create a Storage Account, you can define a parameter of type storageAccountType and use it to create the Storage Account resource as demonstrated above.

param StorageType Constants.storageAccountType

resource storageaccount 'Microsoft.Storage/storageAccounts@2021-02-01' = {
  name: StorageType.name
  location: StorageType.location
  kind: StorageType.kind
  sku: StorageType.sku
  properties: StorageType.properties
}

As shown in the above code example, you just need to use the new type instead of declaring each property required for creation of the storage account.

Use Case 3: Re-using Functions.

Let’s say, you fulfill a requirement of creating a Storage account with different replication strategies based on the environment.

For non-production environments, you can opt for Locally Redundant Storage (LRS) for cost-effectiveness, while for production environments, you may prefer Geo-Redundant Storage (GRS) for higher resilience.

You can learn more about how to re-use code in Bicep using Azure Function in my article Azure Bicep – Refactor common code using User Defined Functions

Conclusion

The introduction of @export() and import attributes in Azure Bicep significantly enhances code reusability and modularity, making it easier to manage and scale Infrastructure-as-Code (IaC) projects. By centralizing shared variables, types, and functions in dedicated files, developers can reduce redundancy, improve maintainability, and simplify complex deployments.

Key takeaways from the article include.

  1. Reusability: Shared components like variables and types can be defined once and reused across multiple files.
  2. Simplified Syntax: Using the import statement, entire sets of variables or types can be easily incorporated into other files.
  3. Logical Organization: Separating constants, types, and functions into distinct files creates a clear, organized structure for IaC projects.
  4. Use Cases in Action: Practical examples demonstrate how to reuse primitive literals, types, and functions to streamline infrastructure templates, such as defining storage accounts and managing replication strategies.

This functionality fosters better collaboration, minimizes errors, and allows developers to focus on innovation rather than repetitive tasks, making Bicep a more powerful tool for cloud resource management.

Up Next
    Ebook Download
    View all
    Learn
    View all