What is Azure Bicep?
Bicep is a domain-specific language (DSL) that uses a declarative syntax to deploy Azure resources. It provides concise syntax, reliable type safety, and support for code reuse.
Note: Bicep CLI version 0.26.X or higher is required to use this feature.
What are user-defined functions?
Different than the standard Bicep functions that are available by default in your Bicep files, user-defined functions are custom made function created by you. They are useful for when you have complicated expressions used repeatedly in your Bicep files and you need to enforce consistent logic.
Limitations
- The function can’t access variables.
- The function can only use parameters that are defined in the function.
- The function can’t use the reference function or any of the list functions.
- Parameters for the function can’t have default values.
Your first function
The output:
Function name | Argument type | Output |
---|---|---|
myFirstFunction | String | Your first message is: Hello, World! |
Examples
Here’s a practical example of a user-defined function that generates network configurations based on the deployment environment:
This function takes an environment parameter and returns a different network configuration based on whether it’s a production environment or not.
Here’s how you would use this function in your main Bicep file:
The function’s output varies depending on the environment:
This example demonstrates how user-defined functions can help manage environment-specific configurations efficiently, reducing code duplication and potential errors.
What I Did Before Functions
Before the introduction of user-defined functions in Bicep, I relied on what I called helper modules. This approach involved creating a separate Bicep file as a module, outputting the result, and using it throughout my codebase. Here’s a quick example:
The usage in the main file would look like this:
This approach served me well for years, and it still has its merits. Some benefits of using helper modules include:
- The ability to encapsulate complex logic and include resource definitions if needed.
- The flexibility to return multiple outputs of various types.
However, user-defined functions offer several advantages over custom modules:
- Faster execution, as functions are evaluated during template compilation rather than at deployment time.
- Easy parameterization and use within the same file, eliminating the need for a separate deployment scope.
- Ideal for simple, repetitive logic that doesn’t involve resource creation.
While both approaches have their place, the introduction of user-defined functions has significantly streamlined many of our common tasks in Bicep.
How I’m Using Functions Today
I’ve recently transitioned from custom helper modules to user-defined functions for all our helper logic. This change has been particularly beneficial for handling structured IP range inputs, which are required by many of our resources but often in different formats.
Here’s an example of how we use these functions:
The outputs from these functions are:
As you can see, while the IP addresses are the same, each resource requires a different format with different parameter names. This variation in required formats makes it an ideal use case for helper functions, allowing us to maintain consistency and reduce errors in our deployments.
Conclusion
User-defined functions in Bicep provide a powerful way to reduce code duplication and enforce consistent logic within your infrastructure-as-code. They offer the flexibility to create both simple and complex functions, allowing you to encapsulate logic as needed.
By using functions instead of custom modules, you can achieve the same benefits of code reuse and consistency while avoiding the additional overhead associated with module deployment. This approach makes them more efficient and easier to maintain.