{"id":29064930,"url":"https://github.com/nnellans/bicep-guide","last_synced_at":"2026-01-24T21:40:12.821Z","repository":{"id":124151731,"uuid":"476748979","full_name":"nnellans/bicep-guide","owner":"nnellans","description":"Bicep Guide","archived":false,"fork":false,"pushed_at":"2025-10-04T16:31:23.000Z","size":294,"stargazers_count":34,"open_issues_count":0,"forks_count":11,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-01-11T00:15:40.318Z","etag":null,"topics":["azure","bicep","iac","infrastructure-as-code"],"latest_commit_sha":null,"homepage":"https://www.nathannellans.com","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nnellans.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-04-01T14:16:45.000Z","updated_at":"2025-10-27T07:01:09.000Z","dependencies_parsed_at":"2025-02-08T22:22:36.647Z","dependency_job_id":"b1d7d0c6-f79e-4507-b467-6351286c1810","html_url":"https://github.com/nnellans/bicep-guide","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/nnellans/bicep-guide","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nnellans%2Fbicep-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nnellans%2Fbicep-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nnellans%2Fbicep-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nnellans%2Fbicep-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nnellans","download_url":"https://codeload.github.com/nnellans/bicep-guide/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nnellans%2Fbicep-guide/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28737562,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-24T21:19:41.845Z","status":"ssl_error","status_checked_at":"2026-01-24T21:13:38.675Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azure","bicep","iac","infrastructure-as-code"],"created_at":"2025-06-27T10:01:05.565Z","updated_at":"2026-01-24T21:40:12.808Z","avatar_url":"https://github.com/nnellans.png","language":"Shell","funding_links":[],"categories":["Community"],"sub_categories":["Community Repositories"],"readme":"# Bicep Guide\n\n- Version: 1.4.0\n- Author:\n  - Nathan Nellans\n  - Email: me@nathannellans.com\n  - Web:\n    - https://www.nathannellans.com\n    - https://github.com/nnellans/bicep-guide\n\n\n\u003e [!IMPORTANT]\n\u003e This is an advanced guide and assumes you already know the basics of Bicep.  Think of this more like an advanced cheat sheet.  I went through various sources, captured any notes that I felt were important, and organized them into the README file you see here.  If you are new to Bicep, then I would suggest going through the Microsoft Docs or doing a couple Microsoft Learn courses first.\n\n\u003e [!WARNING]\n\u003e This is a live document.  Some of the sections are still a work in progress.  I will be continually updating it over time.\n\n\u003e [!NOTE]\n\u003e Here is a link to my own [Bicep Deployment Series](https://www.nathannellans.com/post/all-about-bicep-deploying-bicep-files) which goes over the various nuances of deploying Bicep files.\n\n---\n\n# Bicep Files \u0026 File Names\nBicep files use a `.bicep` file extension and are written using their own custom domain-specific language (DSL).  This guide will detail how to use the DSL to its full potential.\n\nIf you're accustomed to Terraform, you will see that Bicep works differently when it comes to deploying code.  Terraform will combine every `.tf` file in the current directory and deploy them all at the same time.  Whereas Bicep will deploy one main `.bicep` file per deployment.  It is suggested to name this file `main.bicep`\n\nWhen using parameter files, Bicep supports 2 different formats.  If you are storing parameters values in the JSON file format, it is common practice to use the name of the Bicep file and just add the word \"parameters\" like shown below.  If you are using the newer Bicep parameter file format, then just use the name of the Bicep file with the extension of `.bicepparam`.  Support for `.bicepparam` files requires Bicep v0.18.4 or later.\n\n```\nBicep file:           main.bicep\nJSON Parameter file:  main.parameters.json\nBicep Parameter file: main.bicepparam\n```\n\n# Bicep File Structure\nHere are the major sections of a bicep file. This is also the recommended order in which they should appear\n1. [metadata](README.md#1-metadata)\n2. [targetScope](README.md#2-targetscope)\n3. [Parameters](README.md#3-parameters)\n4. [Variables](README.md#4-variables)\n5. [Resources](README.md#5-resources) and/or [Modules](README.md#5-modules)\n6. [Outputs](README.md#6-outputs)\n\n---\n\n# 1. Metadata\n- These are simple key/value pairs that can contain any information you want to include\n- Some good examples are a description, author, creation date, etc.\n- These are optional\n\n```bicep\nmetadata description = 'This file deploys 12 resources'\nmetadata author = 'me@nathannellans.com'\n```\n\n---\n\n# 2. targetScope\n- You can only have 1 `targetScope` entry at the top of your file\n- It can be set to 1 of 4 options, all listed below\n- This specifies the level at which all of the resources in this Bicep file will be deployed (however, you can get around this by using Modules, more on that later)\n- This line is optional.  If you omit it, the default value of `resourceGroup` is used\n- More detailed information about scopes can be found on [my blog](https://www.nathannellans.com/post/deploying-bicep-files-part-6-scopes-stacks)\n\n```bicep\ntargetScope = 'resourceGroup'\ntargetScope = 'subscription'\ntargetScope = 'managementGroup'\ntargetScope = 'tenant'\n```\n\n---\n\n# 3. Parameters\n- Parameters are for values that will change/vary between different deployments\n- Each Parameter must be set to one of the supported Data Types (see below)\n- Optionally, you can use `=` to set a default value for the Parameter\n  - The default value can use expressions, but it can NOT use the `reference` or `list` functions\n\n```bicep\n// Defining Parameters\nparam myParameter1 int\nparam myParameter2 array\nparam myParameter3 string = 'default Value'\n\n// Using Parameters\n// Just use the name of the Parameter\nresource exampleStorageAccount 'Microsoft.Storage/storageAccounts@2021-04-01' = {\n  name: myParameter1\n  location: myParameter2\n}\n```\n\n## Parameter Decorators\n- Decorators are placed directly above the parameter definition\n- You can use more than one decorator for each parameter definition\n- It's good practice to specify the `minLength` and `maxLength` decorators for parameters that control resource naming. These limitations help avoid errors later during deployment. For example, an Azure Storage Account must have a name that is between 3 and 24 characters long\n  - For integers you can specify `minValue` and `maxValue` decorators, instead\n- It's good practice to specify the `description` decorator for all of your parameters. Try to make them helpful\n- The `allowed` decorator can be used to provide allowed values in an array. If the value doesn't match, then the deployment fails\n  - Use this sparingly, as Azure makes changes frequently to things like SKUs and sizes, so you don't want to have an allowed list that is out of date\n- The `metadata` decorator is an object that can contain properties of any name and type. Use this for info that you don't want to put into the `description` decorator\n- The `secure` decorator can be used on `string` and `object` parameters. The value for a secure parameter isn't saved to the deployment history and isn't logged\n  - Make sure you use this parameter in a location that expects a secure value, for example Tag values are stored in plain text, so do not use a secure string parameter in a Tag\n  - Since these are secure, do NOT set a default value, as that will be stored in code\n- The `sealed` decorator can be used on `object` parameters\n  - By default, the `object` type in Bicep will let you pass any properties, even undefined ones. When doing this, Bicep will give a warning code `BCP089` and your deployment will continue.\n  - However, if you provide the `sealed` decorator and then try to pass undefined properties to an `object`, your deployment will now fail with an error.\n- The `discriminator` decorator can be used on parameters that reference user-defined types. More on this in the User-Defined Types section below\n\n```bicep\n@minLength(1)\n@maxLength(80)\n@description('Provide a name for the VirtualWAN resource')\n@allowed([\n  'option1'\n  'option2'\n])\n@secure()\nparam myParameter4 string\n\n@minValue(1)\n@maxValue(20)\n@metadata({\n  key1: 'value1'\n  key2: 'value2'\n})\nparam myParameter5 int\n\n@sealed()\nparam myParameter6 object\n```\n\n## Bicep Data Types:\nBicep data types include:  any, array, bool, int, object, string, and union types\n\n### Any\n- Can be used anywhere type syntax is expected\n- Requires Bicep v0.38.3 or newer\n```bicep\nparam someName any\n```\n\n### Array\n- Arrays use square brackets:  `[ ]`\n```bicep\n// Multi-line arrays (use line breaks to separate values)\nparam someName array = [\n  'one'\n  'two'\n  'three'\n]\n\n// Single-line arrays (use commas to separate values)\n// Requires Bicep v0.7.4 or newer\nparam someName array = [ 'one', 'two', 'three' ]\n```\n- In single-line, a comma after the last value is supported, but not required\n- The data types in an array do NOT have to match, as each item is represented by the 'any' type\n- Bicep arrays are zero-based, so using the example above `someName[0] = 'one'`\n\n### Bool\n- Simply use either `true` or `false` with no quotation marks\n\n```bicep\nparam exampleBoolParameter bool = false\n```\n\n### Int\n- A simple, whole number with no quotation marks\n- In Bicep, these are 64-bit Integers\n- Bicep does NOT support floating point, decimal, or binary yet\n\n```bicep\nparam exampleIntParameter int = 1200\n```\n\n### Object\n- Objects use braces / curly brackets:  `{ }`\n```bicep\n// Multi-line objects (use line breaks to separate pairs)\nparam someName object = {\n  key: 'value'\n  key: 'value'\n}\n\n// Single-line objects (use commas to separate pairs)\n// Requires Bicep v0.7.4 or newer\nparam someName object = { key: 'value', key: 'value' }\n```\n- For single-line, a comma after the last pair is supported, but not required\n- Each property of the Object can be of any type\n- If the key contains special characters, you can enclose the key in single quotes\n- You can use a period to access values, so `exampleObjectParameter.key2 = true`\n- You can also use brackets to access values, so `exampleObjectParameter['key4'].keyA = 'value2'`\n- Complex object example:\n  ```bicep\n  param exampleObjectParameter object = {\n    key1: 'value'\n    key2: true\n    'special.key3': 150\n    key4: {\n      keyA: 'value2'\n    }\n  }\n  ```\n\n### String (single-line)\n- Bicep uses single quotes for single-line strings\n- All Unicode characters with code points between 0 and 10FFFF (both inclusive) are allowed\n- Escape Characters:\n  - Use `\\\\` for `\\`\n  - Use `\\'` for `'` (single quote)\n  - Use `\\n` for line feed (LF)\n  - Use `\\r` for carriage return (CR)\n  - Use `\\t` for tab\n  - Use `\\u{###}` for unicode characters\n  - Use `\\$` for `$` (dollar sign) (this is only needed if you must type `${` and you're NOT using interpolation)\n\n```bicep\nparam exampleStringParameter string = 'example string'\n```\n\n### String (multi-line)\n- Opening sequence is `'''` (three single quotes)\n- Closing sequence is `'''` (three single quotes)\n- Everything in-between is read verbatim\n- Escape characters are NOT not possible inside the string\n- You can NOT include `'''` (three single quotes) inside your multi-line string\n- Bicep does NOT support interpolation inside your multi-line string yet\n\n```bicep\nparam exampleMultilineParameter string = '''\nthis\n  is\n    an\n      idented\n        example\n'''\n```\n\n### Custom User-Defined Types\nStarting with Bicep v0.21.1, you can create your own user-defined types\n\n```bicep\n// This custom type defines a string, and sets 3 allowed values\ntype myCustomType1 = 'azure' | 'gcp' | 'aws'\n\n// To define an array put [] at the end\n// This custom type defines an array of strings\ntype myCustomType2 = string[]\n\n// This custom type defines an array of strings, and only allows certain values in the array\ntype myCustomType3 = ('one' | 'two' | 'three')[]\n\n// This custom type defines an object of mixed types\ntype myCustomType4 = {\n  name: string\n  age: int\n  gender: string?  // The ? at the end marks this as optional\n}\n\n// Then, in your parameter, use this custom type instead of the standard types like `string`, `bool`, etc.\nparam someParamName myCustomType3\n\n// Option 2, simply define the custom type inline in your parameter (this defines an array of objects)\nparam someParamName {\n  name: string\n  age: int\n}[]\n```\n\nCustom User-Defined Types support the following decorators:\n- `description()`\n- `discriminator()` for object types\n- `maxLength()` and `minLength()` for arrays and strings\n- `maxValue()` and `minValue()` for ints\n- `metadata()`\n- `sealed()` for objects\n- `secure()` for strings and objects\n\nAlso see: [Import / Export](README.md#import--export)\n\n### Custom-tagged Union Data Type\nThere is a special type of User-defined Type called Custom-tagged Union Data Type\n\n- This represents a parameter value that can be one of several different types and is denoted by the `discriminator()` decorator\n- The `discriminator()` decorator takes a single parameter\n  - The parameter must be a shared property name that is common between all of the union types\n  - The value of this shared property must be unique in all of the union types\n\n```bicep\n// define the first custom union type, which uses 2 integer values\ntype firstUnionType = {\n  sharedProperty: 'numberOne'\n  property1: int\n  property2: int\n}\n\n// define the second custom union type, which uses 3 string values\ntype secondUnionType = {\n  sharedProperty = 'numberTwo'\n  propertyA: string\n  propertyB: string\n  propertyC: string\n\n// now define a parameter that can use either type based on the discriminator\n@discriminator('sharedProperty')\nparam someParamName firstUnionType | secondUnionType\n```\n\nIn the above example, if the value provided for this parameter includes `sharedProperty = 'numberOne'`, then the value will be validated against the custom type `firstUnionType`\n\n\u003e [!NOTE]  \n\u003e You can even do multiple levels of Custom-tagged Union Data Types by using the `discriminator()` decorator on your `type` definitions\n\n---\n\n# 4. Variables\n- Instead of embedding complex expressions directly into resource properties, use variables to contain the expressions\n- This approach makes your Bicep file easier to read and understand. It avoids cluttering your resource definitions with logic\n- When you define a variable, the data type isn't needed. Variables infer the type from the resolved value\n  - Starting with Bicep v0.36.1, you can optionally provide a data type for your variables\n- The value of the variable can use all available expressions, including the `reference` or `list` functions\n\n```bicep\n// Defining Variables\nvar myVariable1 = 'some value for the var'\n\n// With optional type\nvar myVariable2 string = 'some value'\n\n// Using Variables\n// Just use the name of the Variable\nresource exampleStorageAccount 'Microsoft.Storage/storageAccounts@2021-04-01' = {\n  name: myVariable1\n}\n```\n\nAlso see: [Import / Export](README.md#import--export)\n\n---\n\n# 5. Resources\n- It's a good idea to use a recent API version for each resource. New features in Azure services are sometimes available only in newer API versions\n- When possible, avoid using the `reference` and `resourceId` functions in your Bicep file. You can access any resource in Bicep by using the symbolic name. By using the symbolic name, you create an implicit dependency between resources\n- You can still create explicit dependencies by using a `dependsOn` block, but see notes below about this\n\n```bicep\nresource myResource1 'Microsoft.Network/virtualWans@2021-02-01' = {\n  name: 'resourceName'\n  location: 'location'\n\n  // Even though explicit dependencies are sometimes required, the need for them is rare\n  // In most cases, you can use a symbolic name to imply the dependency between resources\n  // If you are setting explicit dependencies, you should consider if there's a way to remove it\n  dependsOn: [\n    myResource2\n    myResource3\n  ]\n}\n```\n\n## `onlyIfNotExists` Decorator\nStarting with Bicep v0.38.3 you can use a new decorator on your resources called `onlyIfNotExists()`.  As the name suggests, the resource will only be deployed if it does not already exist.\n\n```bicep\n@onlyIfNotExists()\nresource myResource 'Microsoft.Storage/storageAccounts@2019-06-01' = {\n  name: 'examplestorageaccount'\n}\n```\n\n## Existing Resources:\nTo reference a resource that already exists, use the `existing` keyword in a resource declaration\n\nHow to define an existing resource in the same targetScope as the current deployment\n\n```bicep\nresource myResource2 'Microsoft.Storage/storageAccounts@2019-06-01' existing = {\n  name: 'examplestorageaccount'\n}\n```\n\nOptionally, you can set the `scope` property to access an existing resource in a different scope\n- More detailed information about scopes can be found on [my blog](https://www.nathannellans.com/post/deploying-bicep-files-part-6-scopes-stacks)\n\n```bicep\nresource myResource3 'Microsoft.Storage/storageAccounts@2019-06-01' existing = {\n  name: 'examplestorage'\n  scope: resourceGroup(otherRG)\n}\n```\n\n## Child Resources:\n- Child resources are resources that exist only within the context of another resource\n- Each 'parent' resource accepts only certain 'child' resources.  Check out the [Bicep Resource Reference](https://docs.microsoft.com/en-us/azure/templates/) for the supported parent/child relationships.\n- There are different ways you can declare a child resource:\n\n### Method 1. Child resource included within the Parent resource\n- 'resourceType' for children can be the simple name `shares`, since the full resourceType path `Microsoft.Storage/storageAccounts/fileServices/shares` is assumed from the parent resource\n- 'apiVersion' for children is optional, and if omitted the children will use the apiVersion of the parent resource\n- 'name' for children can be the simple name `secondChildName`, since the full name `parentName/childName/secondChildName` is assumed from the parent resource\n- Children can reference Parent resources with symbolic naming. But, Parents can NOT reference Child resources, this would cause a cyclic-dependency\n\n```bicep\nresource parentSymbolicName 'Microsoft.Storage/storageAccounts@2021-04-01' = {\n  name: 'parentName'\n  propertiesOfParent\n  propertiesOfParent\n\n  resource childSymbolicName 'fileServices' = {\n    name: 'childName'\n    propertiesOfChild\n    propertiesOfChild\n\n    resource secondChildSymbolicName 'shares' = {\n      name: 'secondChildName'\n      propertiesOfSecondChild\n    }\n  }\n}\n```\n\n### Method 2. The Child resources are defined separately in their own top-level resource\n- The Child resource uses a `parent` parameter that points to the symbolic name of the parent resource\n- Benefit over Method 1: allows you to define the Child resources in a different Bicep file than the Parent resources\n- Benefit over Method 1: allows you to use a loop on Child resources\n- The 'resourceType' for children must be the full resourceType path `Microsoft.Storage/storageAccounts/fileServices/shares`\n- The 'apiVersion' for children must be provided\n- The 'name' for children can be just the simple name `childName`, since the full name `parentName/childName` is assumed from the parent resource\n\n```bicep\nresource childSymbolicName 'Microsoft.Storage/storageAccounts/fileServices@2021-04-01' = {\n  parent: parentSymbolicName\n  name: 'childName'\n  propertiesOfChild\n  propertiesOfChild\n}\n```\n\n### Method 3. The Child resources are defined separately in their own top-level resource (same as above)\n- At first glance, this looks the same as Method 2.  But, with Method 3 the Child resource does NOT use a `parent` parameter\n- The 'resourceType' for children must be the full resourceType path `Microsoft.Storage/storageAccounts/fileServices`\n- The 'apiVersion' for children must be provided\n- The 'name' for children must be the full name `parentName/childName`\n- Dependencies are NOT inferred with this method, so you must include a `dependsOn` block and manually set dependencies as needed\n- This method is NOT recommended\n\n```bicep\nresource secondChildSymbolicName 'Microsoft.Storage/storageAccounts/fileServices@2021-04-01' = {\n  name: 'parentName/childName'\n  propertiesOfChild\n  propertiesOfChild\n\n  dependsOn: [\n    parentSymbolicName\n  ]\n}\n```\n\n## Extension Resources:\n- An extension resource is meant to modify another resource\n- A full list of extension resources can be [found here](https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/extension-resource-types)\n\nExample 1: By default, an extension resource will target what you have in your `targetScope` parameter\n\n```bicep\nresource myExtensionResource1 'Microsoft.Authorization/locks@2016-09-01' = {\n  name: 'lockName'\n  properties: {\n    level: 'CanNotDelete'\n  }\n}\n```\n\nExample 2: This example sets the `targetScope` to `subscription`, so this extension resource will target a Subscription\n\n```bicep\ntargetScope = 'subscription'\nresource myExtensionResource2 'Microsoft.Authorization/roleAssignments@2020-10-01-preview' = {\n  name: 'roleAssignmentName'\n  properties: {\n    principalId: 'idOfPrincipal'\n    roleDefinitionId: 'idOfRole'\n  }\n}\n```\n\nExample 3: Deploy an Extension Resource to a specific resource using the `scope` parameter\n- This example creates a Role Assignment on the resource which has the symbolic name 'myResource3'\n\n```bicep\nresource myExtensionResource3 'Microsoft.Authorization/roleAssignments@2020-10-01-preview' = {\n  name: 'roleAssignmentName'\n  scope: myResource3\n  properties: {\n    principalId: 'idOfPrincipal'\n    roleDefinitionId: 'idOfRole'\n  }\n}\n```\n\nMore detailed information about scopes can be found on [my blog](https://www.nathannellans.com/post/deploying-bicep-files-part-6-scopes-stacks)\n\n---\n\n# 5. Modules\n- A module is just a Bicep file that is deployed from another Bicep file, allowing you to reuse code\n- The module (Bicep file) can be a local file or stored in a Registry\n- The `name` property is optional starting with Bicep v0.34.1\n  - It becomes the name of the nested deployment resource in the generated ARM template\n  - If no name is provided, a GUID will be generated as the name for the nested deployment resource\n- Starting with Bicep v0.35.1, the `secure()` decorator is also supported on `module` outputs. You can now output secure values from a child module and read them in a parent module\n\n```bicep\nmodule myModule1 '../someFile1.bicep' = {\n  name: 'myModule1Deployment' // optional\n  params: {\n    myModule1Param1: 'something'\n    myModule1Param2: 'something'\n    myModule1Param3: 'something'\n  }\n}\n```\n\nHow to deploy a Module to a different scope using the `scope` parameter\n\u003e [!NOTE]\n\u003e This is how you can deploy resources to a scope that is different than your 'targetScope' parameter\n\u003e \n\u003e More detailed information about scopes can be found on [my blog](https://www.nathannellans.com/post/deploying-bicep-files-part-6-scopes-stacks)\n\n```bicep\nmodule myModule2 '../someFile2.bicep' = {\n  name: 'myModule2Deployment'\n  scope: subscription('xxxx')\n  params: {\n    myModule2Param1: 'something'\n    myModule2Param2: 'something'\n    myModule2Param3: 'something'\n  }\n}\n```\n\nHow to use a Module (Bicep file) in a Registry\n- `br:` is the schema name for a Bicep Registry\n- Optionally, you can configure Bicep Registry 'aliases' in your `bicepconfig.json` file and use the alias instead of the full registry path.  See this for [more info](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-config-modules)\n  - Starting with Bicep v0.5.6 there is a default alias called `public` which points at Microsoft's official AVM (Azure Verified Modules).\n  - An example would be:  `br/public:avm/res/network/virtual-network:0.7`\n  - [Here is a link](https://github.com/Azure/bicep-registry-modules) to the official GitHub repo containing the currently published modules\n\n```bicep\nmodule myModule3 'br:exampleregistry.azurecr.io/bicep/modules/storage:v1' = {\n```\n\nHow to add a User-Assigned Managed Identity to a Module\n- Requires Bicep v0.38.3 or newer\n- This makes the identity available within the module. For example, to access a Key Vault.\n- The [docs](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/modules#module-identity) still state that \"this capability is intended for future use and is not yet supported by backend services.\"\n\n```bicep\nparam identityId string\n\nmodule myModule4 '../someFile4.bicep' = {\n  identity: {\n    type: 'UserAssigned'\n    userAssignedIdentities: {\n      '${identityId}': {}\n    }\n  }\n  ...\n}\n```\n\n---\n\n# 6. Outputs\n- Use Outputs when you need to return certain values from a deployment\n- Make sure you don't create regular outputs for sensitive data. Output values can be accessed by anyone who can view the deployment history. They're NOT appropriate for handling secrets. In this case use the `secure()` decorator\n- Instead of passing property values around through outputs, use the `existing` keyword to look up properties of resources that already exist. It's a best practice to look up keys from other resources in this way instead of passing them around through outputs. You'll always get the most up-to-date data\n- Outputs must set a specific data type\n- Outputs support the following decorators:\n  - `description()`\n  - `discriminator()` for object types\n  - `maxLength()` and `minLength()` for arrays and strings\n  - `maxValue()` and `minValue()` for ints\n  - `metadata()`\n  - `sealed()` for objects\n  - `secure()` for strings and objects\n    - Supported with Bicep v0.18.4 or later\n    - This prevents the value from being logged or displayed in deployment history, Azure portal, or command-line outputs.\n    - Starting with Bicep v0.35.1, the `secure()` decorator is also supported on `module` outputs. You can now output secure values from a child module and read them in a parent module\n\n```bicep\noutput myOutput1 int = myResource4.properties.maxNumberOfRecordSets\n\n@secure()\noutput myOutput2 string = myResource4.properties.maxNumberOfRecordSets\n```\n\nIf the property being returned has a hyphen in the name, you can NOT use the dot notation as shown above.  Instead, you must use brackets around the property\n\n```bicep\noutput myOutput2 string = myResource1['some-property']\n```\n\nYou can programmatically grab outputs from successful deployments\n\nPowerShell:\n```powershell\n(Get-AzResourceGroupDeployment -ResourceGroupName \u003crgName\u003e -Name \u003cdeploymentName\u003e).Outputs.myOutput1.value\n```\n\nAzure CLI:\n```\naz deployment group show -g \u003crgName\u003e -n \u003cdeploymentName\u003e --query properties.outputs.myOutput2.value\n```\n\n---\n\n# Other Topics\n\n- [Parameter Files](README.md#parameter-files)\n- [Conditions (If)](README.md#conditions-if)\n- [Loops](README.md#loops)\n- Miscellaneous\n  - [Comments](README.md#comments)\n  - [String Interpolation](README.md#string-interpolation)\n  - [Ternary Operator](README.md#ternary-operator)\n  - [Functions](README.md#functions)\n  - [Import / Export](README.md#import--export)\n\n---\n\n# Parameter Files\n\nInstead of storing parameter values directly in your `.bicep` file, you can store the values externally in a `.bicepparam` or `.json` file.  Then, you'd pass this parameter file, along with the `.bicep` file, to your deployment.\n\n\u003e [!NOTE]\n\u003e This guide is only going to cover the newer `.bicepparam` files.  If you'd like to know more about the older `.json` parameter files, then please reference [the documentation](https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/parameter-files).\n\nFormat of a `.bicepparam` file\n```bicep\n// the using statement\nusing 'something'\n\n// optional variables\nvar varName1 = value1\nvar varName2 = value2\n\n// parameter values\nparam parName1 = value1\nparam parName2 = readEnvironmentVariable('someEnvVar')\nparam parName3 = toLower(value3)\nparam parName4 = az.getSecret('subscriptionId', 'resourceGroupName', 'keyvaultName', 'secretName', 'secretVersion')\n```\n\nEach `.bicepparam` file is tied to a particular `.bicep` file.  This relationship is defined by the `using` statement.  There are multiple options for defining the `using` statement, see below for more.\n\n```bicep\n// a regular bicep file or arm template\nusing 'path/to/file.bicep'\nusing 'path/to/file.json'\n\n// a module from the public bicep registry\nusing 'br/public:path:tag'\n\n// a module from a private bicep registry\nusing 'br:registryName.azurecr.io/bicep/path:tag'\nusing 'br/aliasName:path:tag'\n\n// a template spec\nusing 'ts:subscriptionId/resourceGroupName/specName:tag'\nusing 'ts/aliasName:specName:tag'\n\n// NOT tied to anything\nusing none\n```\n\nStarting with Bicep v0.22.6, you can reference ARM Templates, Bicep Registries, and Template Specs in your `.bicepparam` files\n\nStarting with Bicep v0.21.1 you can optionally define Variables in your `.bicepparam` files.\n\nYou can use expressions in the value of each parameter.\n- Use the `readEnvironmentVariable` function to pull a value from an environment variable.\n- Don't store sensitive values in your parameter files.  Instead, use the `az.getSecret` function to pull the value from Key Vault.\n  - The `az.getSecret` function can only pull secrets from Key Vault.\n  - The `az.getSecret` function can only be used in a `param` value\n  - The `az.getSecret` function only supports params that have the `@secure()` decorator\n  - By default, it will pull the latest version of the secret, unless you specify the `secretVersion` parameter\n\nAlso see: [Import / Export](README.md#import--export)\n\n# Conditions (If)\nYou can deploy a resource only if a certain condition is met, otherwise the resource will not be deployed\n\n```bicep\nresource myResource4 'Microsoft.Network/dnszones@2018-05-01' = if (condition) {\n  name: 'myZone'\n  location: 'global'\n}\n```\n\nNote 1:\n- ARM evaluates the expressions used inside resource properties before it evaluates the conditional on the resource itself\n- Example:\n  - ResourceB has properties which are referencing the symbolicName of ResourceA\n  - ResourceA has a condition where it will not be deployed\n  - ResourceB's references to ResourceA are now invalid, and the deployment will fail with a 'ResourceNotFound' error\n  - This will fail even if ResourceB has the same condition applied to it as ResourceA\n- Use the ternary operator on the properties of ResourceB as a workaround\n\nNote 2:\n- You can't define two resources with the same name in the same Bicep file and then use a condition to only deploy one of them\n- The deployment will fail, because Resource Manager views this as a conflict\n- If you have several resources, all with the same condition for deployment, consider using Bicep Modules. You can create a Module that deploys all the resources, and then put a condition on the module declaration in your main Bicep file.\n\n# Loops\n- To deploy more than one instance of an item, add the `for` expression\n- Loops are supported on: Variables, Resources, Modules, Properties, Outputs\n- Optionally, you can use the `@batchSize()` decorator to specify how many can be created at one time\n\nExample 1: Integer Index\n\n```bicep\n@batchSize(int)\nresource myResource5 'Microsoft.Storage/storageAccounts@2021-08-01' = [for i in range(int1,int2): {\n  name:  'something-${i}'\n}]\n```\n\nExample 2: Array elements\n\n```bicep\n@batchSize(int)\nresource myResource6 'Microsoft.Storage/storageAccounts@2021-08-01' = [for item in array: {\n  name: item.property1\n}]\n```\n\nExample 3: Array and Index\n\n```bicep\n@batchSize(int)\nresource myResource7 'Microsoft.Storage/storageAccounts@2021-08-01' = [for (item, i) in array: {\n  name: 'something-${i}'\n  location: item.property1\n}]\n```\n\nExample 4: Complex Object / Dictionary\n\n```bicep\n@batchSize(int)\nresource myResource8 'Microsoft.Storage/storageAccounts@2021-08-01' = [for item in items(object): {\n  name: item.value.property1\n}]\n```\n\nHow to create a Resource with a loop and a condition\n\n```bicep\n@batchSize(int)\nresource myResource9 'Microsoft.Storage/storageAccounts@2021-08-01' = [for item in array: if(item.property1 == true) {\n  name: item.property2\n}]\n```\n\n---\n\n# Miscellaneous\n\n## Comments\n\n```bicep\n// This is a single-line comment\n\n/*\nThis is a \nmulti-line comment\n*/\n```\n\n## String Interpolation\n- All strings in Bicep support interpolation\n- To inject an expression surround it by `${` and `}`\n\n```bicep\nvar lastName = 'Anderson'\nvar firstName = 'Thomas'\nvar fullName = '${lastName}, ${firstName}'\n```\n\n## Ternary Operator\n\nThe ternary operator is a way to embed an if/then/else statement inside the properties of a resource.\n\n```bicep\ncondition ? valueIfTrue : valueIfFalse\n```\n\nThe true or false values can be of any data type: string, integer, boolean, object, array\n\n## Functions\n\nBicep has a large assortment of functions that can be used in your template.  Check out the [officials docs](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions) for more information about all of the available Functions and their instructions.\n\n### `deployer()` Function\n- Use the deployer function to capture information about the account being used for the deployment\n- `deployer().tenantId` is available starting with Bicep v0.32.4\n- `deployer().objectId` is available starting with Bicep v0.32.4\n- `deployer().userPrincipalName` is available starting with Bicep v0.36.1\n\n### User-defined Functions\n- Support for User-defined Functions requires Bicep v0.26.54 or later\n- Allows you to create and use your own custom functions within a Bicep file\n- Great for when you have complicated expressions that are used repeatedly in your Bicep files\n- They can be nested, you can call a User-defined Function from another User-defined function\n- They support custom User-defined Data Types\n- Some limitations:\n  - Can't access variables\n  - Can only use parameters that are defined in the function\n    - Parameters defined in the function can't have default values\n  - Can't use the `reference` or `list` functions\n- [Read the docs](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/user-defined-functions) for more information on User-defined Functions\n- Also see: [Import / Export](README.md#import--export)\n\n```bicep\n// create a user-defined function\nfunc functionName (argName dataType, argName dataType, ...) functionDataType =\u003e expression\n\n// first, define the functionName that you want to give to this user-defined function\n// then, define any arguments that the function uses, specify a name and a data type for each argument\n// then, define the data type of the function's return value\n// finally, define what value the function will return by creating a custom expression that uses the arguments\n```\n\n### Lambda Expressions\n- Lambda Expressions can only be used as arguments on the following specific functions:\n  - `filter()`, `map()`, `reduce()`, `sort()` - Supported with Bicep v0.10.61 onward\n  - `toObject()` - Supported with Bicep v0.14.6 onward\n  - `groupBy()`, `mapValues()` - Supported with Bicep v0.27.1 onward\n- The general format of a Lambda Expression is `lambdaVariable =\u003e lambdaExpression`.\n- [Read the docs](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions-lambda) for more information and examples for Lamba Expressions.\n\n#### Example: `filter()`\n\n```bicep\nfilter(inputArray, lambdaExpression)\n// input: array\n// lambaExpression: expression/test to run against each element of the array\n//   - Supports an optional index as of Bicep v0.27.1\n// output: array (containing only elements that passed the test)\n\n// example\nvar inputArray = [\n  {\n    name: 'Reba'\n    age: 24\n  }\n  {\n    name: 'Garth'\n    age: 10\n  }\n]\n\noutput someOutput array = filter(inputArray, item =\u003e item.age \u003e 15)\n// This returns only elements of the array that have an age value greater than 15,\nsomeOutput = [\n  {\n    name: 'Reba'\n    age: 24\n  }\n]\n```\n\n#### Example: `groupBy()`\n\n```bicep\ngroupBy(inputArray, lambdaExpression)\n// input: array\n// lambdaExpression: the expression used to group the array elements \n// output: object (containing the grouped elements)\n\n//example\nvar inputArray = ['Reba', 'Rodney', 'Garth', 'Gary']\n\noutput someOutput object = groupBy(inputArray, item =\u003e substring(item, 0, 1))\n// This returns an object which groups the array elements by their first character\nsomeOutput = {\n  R: ['Reba', 'Rodney']\n  G: ['Garth', 'Gary']\n}\n```\n\n#### Example: `map()`\n\n```bicep\nmap(inputArray, lambdaExpression)\n// input: array\n// lambaExpression: whatever manipulation you want\n//   - Supports an optional index as of Bicep v0.27.1\n// output: array (containing your manipulated elements)\n\n// example\nvar inputArray = [\n  {\n    name: 'Reba'\n    age: 24\n  }\n  {\n    name: 'Garth'\n    age: 10\n  }\n]\n\noutput someOutput1 array = map(inputArray, item =\u003e item.name)\n// This returns an array containing just the values of each name:\nsomeOutput1 = [\n  'Reba'\n  'Garth'\n]\n\noutput someOutput2 array = map(inputArray, item =\u003e 'Hello ${item.name}!')\n// This returns an array which concatenates text to each name:\nsomeOutput2 = [\n  'Hello Reba!'\n  'Hello Garth!'\n]\n```\n\n#### Example: `mapValues()`\n\n```bicep\nmapValues(inputObject, lambdaExpression)\n// input: object\n// lambdaExpression: the expression used to modify each value\n// output: object (containing modified values)\n\n// example\nvar inputObject = {\n  something: 'foo'\n  anotherthing: 'bar'\n}\n\noutput someOutput object = mapValues(inputObject, item =\u003e toUpper(item))\n// This returns the same object, but with modified values. In this case, the values are converted to uppercase:\nsomeOutput = {\n  something: 'FOO'\n  anotherthing: 'BAR'\n}\n```\n\n#### Example: `reduce()`\n\n```bicep\nreduce(inputArray, initialValue, lambdaExpression)\n// input: array\n// initialValue: the initial starting value for comparison\n// lambdaExpression: expression used to aggregate the current value with the next value\n//   - Supports an optional index as of Bicep v0.27.1\n// output: any\n\nvar inputArray = [5, 3, 2, 8]\n\noutput someOutput int = reduce(inputArray, 0, (currentItem, nextItem) =\u003e currentItem + nextItem)\n// This returns an integer which is the result of adding each item in the array to the next item, starting with 0\n// For example: ((((0 + 5) + 3) + 2) + 8)\nsomeOutput = 18\n```\n\n#### Example: `sort()`\n\n```bicep\nsort(inputArray, lambdaExpression)\n// input: array\n// lambdaExpression: an expression that compares one array element to another\n// output: array (elements are sorted per your expression)\n\n// example\nvar inputArray = [\n  {\n    name: 'Reba'\n    age: 24\n  }\n  {\n    name: 'Garth'\n    age: 10\n  }\n  {\n    name: 'Toby'\n    age: 2\n  }\n]\n\noutput someOutput array = sort(inputArray, (item1, item2) =\u003e item1.age \u003c item2.age)\n// This returns an array with the exact same elements, however they are sorted by age, lowest to highest\nsomeOutput = [\n  {\n    name: 'Toby'\n    age: 2\n  }\n  {\n    name: 'Garth'\n    age: 10\n  }\n  {\n    name: 'Reba'\n    age: 24\n  }\n]\n```\n\n#### Example: `toObject()`\n\n```bicep\ntoObject(inputArray, lambdaExpression, [lambdaExpression])\n// input: array\n// lambdaExpression: defines the key of each element for the output object\n// optional lambdaExpression: defines the value of each element for the output object\n// output: object\n\n// example\nvar inputArray = [\n  {\n    name: 'Reba'\n    age: 24\n  }\n  {\n    name: 'Garth'\n    age: 10\n  }\n]\n\noutput someOutput1 object = toObject(inputArray, item =\u003e item.name)\n// This creates a dictionary object, where the key of each element is the 'name'\n// Since the optional 2nd lambdaExpression was omitted, then the value becomes the original array element\nsomeOutput1 = {\n  Reba: {\n    name: 'Reba'\n    age: 24\n  }\n  Garth: {\n    name: 'Garth'\n    age: 10\n  }\n}\n\noutput someOutput2 object = toObject(inputArray, item =\u003e item.name, item =\u003e item.age)\n// This creates a dictionary object, where the key of each element is the 'name' and the value of each one is 'age'\n// This example includes the optional 2nd lambaExpression, and we get a return value like this:\nsomeOutput2 = {\n  Reba: 24\n  Garth: 10\n}\n```\n\n### Import / Export\n- First, you must mark an item as being exportable.  You can specify the `@export()` decorator on any User-defined Type (`type`), User-defined Function (`func`), or Variable (`var`)\n- Then, you can use the `import` function, in a totally different Bicep file, to import that `type`, `func`, or `var` from the first Bicep file.\n- Support for Compile-time Imports is generally available as of Bicep v0.25.3\n\nExample `exports.bicep` file:\n```bicep\n@export()\ntype myUserDefinedType = {\n  something: string\n  anotherthing: int\n}\n\n@export()\nfunc myUserDefinedFunction(name string) string =\u003e 'Hey there ${name}'\n\n@export()\nvar myVariable = 'some constant value'\n// can only use constant values, or references to other variables\n// can not use references to resources, modules, or parameters\n```\n\nExample `main.bicep` file:\n```bicep\n// method 1, import the given items from exports.bicep\nimport {myUserDefinedType, myVariable} from 'exports.bicep'\n\n// method 1, same as above, but define an optional alias that you can use\nimport {myVariable as newVariableAlias} from 'exports.bicep'\n\n// method 2, import everything from exports.bicep into the symbolic name allImports\n// then reference each item like so:  allImports.myUserDefinedType, allImports.myUserDefinedFunction, allImports.myVariable\nimport * as allImports from 'exports.bicep'\n```\n\nSupport for `.bicepparam` files\n- As of Bicep v0.22.6, you can import Variables in your `.bicepparam` files\n- As of Bicep v0.26.54, you can import User-defined Functions in your `.bicepparam` files\n\n---\n\n## Examples of getting info from ARM Resource Provider (WIP)\n\nPowerShell:\n```powershell\n((Get-AzResourceProvider -ProviderNamespace Microsoft.Batch).ResourceTypes | Where-Object ResourceTypeName -eq batchAccounts).Locations\n```\n\nAzure CLI:\n```\naz provider show --namespace Microsoft.Batch --query \"resourceTypes[?resourceType=='batchAccounts'].locations | [0]\" --out table\n```\n\n---\n\n## Templates for Deploying Bicep\n\nI've written a whole series of articles describing the different methods that can be used to deploy Bicep:\n- [Part 2 - Deploying with Az CLI](https://www.nathannellans.com/post/deploying-bicep-files-part-2-az-cli)\n- [Part 3 - Deploying with Az PowerShell Module](https://www.nathannellans.com/post/deploying-bicep-files-part-3-az-powershell-module)\n- [Part 4 - Deploying with Azure DevOps Pipelines](https://www.nathannellans.com/post/deploying-bicep-files-part-4-azure-devops-pipelines)\n- [Part 5 - Deploying with GitHub Actions](https://www.nathannellans.com/post/deploying-bicep-files-part-5-github-actions)\n\nI've also included some example files in this repo:\n- [Az CLI examples](./deployment-options/az-cli.sh)\n- [Az PowerShell Module examples](./deployment-options/az-powershell-module.ps1)\n- [Azure DevOps Pipelines examples](./deployment-options/azure-devops-pipelines.yml)\n- [GitHub Actions examples](./deployment-options/github-actions.yml)\n\n## Templates for Deployment Stacks\n\nDeployment Stacks are currently not featured in the guide you're reading, but I have blogged about them:\n- [Part 6 - Deployment Scopes \u0026 Deployment Stacks](https://www.nathannellans.com/post/deploying-bicep-files-part-6-scopes-stacks)\n\nI've also included some example files in this repo for Deployment Stacks:\n- [Az CLI examples](https://github.com/nnellans/bicep-guide/blob/main/deployment-options/az-cli-stacks.sh)\n- [Az PowerShell Module examples](https://github.com/nnellans/bicep-guide/blob/main/deployment-options/az-powershell-module-stacks.ps1)\n- [GitHub Actions examples](https://github.com/nnellans/bicep-guide/blob/main/deployment-options/github-actions-stacks.yml)\n\n---\n\n# Links\n- [Bicep Resource Reference](https://docs.microsoft.com/en-us/azure/templates/)\n- [Understand the structure and syntax of Bicep files](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/file)\n- [Bicep Best Practices](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/best-practices)\n- [Bicep Functions](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions)\n- [Bicep Operators](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/operators)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnnellans%2Fbicep-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnnellans%2Fbicep-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnnellans%2Fbicep-guide/lists"}