User-defined functions in Bicep

Within your Bicep file, you can create your own functions. These functions are available for use in your Bicep files. User-defined functions are separate from the standard Bicep functions that are automatically available within your Bicep files. Create your own functions when you have complicated expressions that are used repeatedly in your Bicep files.

Bicep CLI version 0.26.X or higher is required to use this feature.

Limitations

There are some restrictions when defining a user function:

  • 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.

Define functions

Use the func statement to define user-defined functions.

@<decorator>(<argument>)
func <user-defined-function-name> (<argument-name> <data-type>, <argument-name> <data-type>, ...) <function-data-type> => <expression>

Examples

The following examples show how to define and use user-defined functions:

func buildUrl(https bool, hostname string, path string) string => '${https ? 'https' : 'http'}://${hostname}${empty(path) ? '' : '/${path}'}'

func sayHelloString(name string) string => 'Hi ${name}!'

func sayHelloObject(name string) object => {
  hello: 'Hi ${name}!'
}

func nameArray(name string) array => [
  name
]

func addNameArray(name string) array => [
  'Mary'
  'Bob'
  name
]

output azureUrl string = buildUrl(true, 'microsoft.com', 'azure')
output greetingArray array = map(['Evie', 'Casper'], name => sayHelloString(name))
output greetingObject object = sayHelloObject('John')
output nameArray array = nameArray('John')
output addNameArray array = addNameArray('John')

The outputs from the preceding examples are:

Name Type Value
azureUrl String https://microsoft.com/azure
greetingArray Array ["Hi Evie!","Hi Casper!"]
greetingObject Object {"hello":"Hi John!"}
nameArray Array ["John"]
addNameArray Array ["Mary","Bob","John"]

With Bicep CLI version 0.23.X or higher, you have the flexibility to invoke another user-defined function within a user-defined function. In the preceding example, with the function definition of sayHelloString, you can redefine the sayHelloObject function as:

func sayHelloObject(name string) object => {
  hello: sayHelloString(name)
}

User-defined functions support using user-defined data types. For example:

@minValue(0)
type positiveInt = int

func typedArg(input string[]) positiveInt => length(input)

param inArray array = [
  'Bicep'
  'ARM'
  'Terraform'
]

output elements positiveInt = typedArg(inArray)

The output from the preceding example is:

Name Type Value
elements positiveInt 3

Use decorators

Decorators are written in the format @expression and are placed above function declarations. The following table shows the available decorators for functions.

Decorator Argument Description
description string Provide descriptions for the function.
export none Indicates that the function is available for import by another Bicep file.
metadata object Custom properties to apply to the function. Can include a description property that is equivalent to the description decorator.

Decorators are in the sys namespace. If you need to differentiate a decorator from another item with the same name, preface the decorator with sys. For example, if your Bicep file includes a variable named description, you must add the sys namespace when using the description decorator.

Description

To add explanation, add a description to function declaration. For example:

@description('The say hello function.')
func sayHelloString(name string) string => 'Hi ${name}!'

Markdown-formatted text can be used for the description text.

Export

Use @export() to share the function with other Bicep files. For more information, see Export variables, types, and functions.

Metadata

If you have custom properties that you want to apply to a user-defined function, add a metadata decorator. Within the metadata, define an object with the custom names and values. The object you define for the metadata can contain properties of any name and type.

You might use this decorator to track information about the function that doesn't make sense to add to the description.

@description('Configuration values that are applied when the application starts.')
@metadata({
  source: 'database'
  contact: 'Web team'
})
type settings object

When you provide a @metadata() decorator with a property that conflicts with another decorator, that decorator always takes precedence over anything in the @metadata() decorator. So, the conflicting property within the @metadata() value is redundant and will be replaced. For more information, see No conflicting metadata.

Next steps