Azure Resource Manager template specs in Bicep

A template spec is a resource type for storing an Azure Resource Manager template (ARM template) for later deployment. This resource type enables you to share ARM templates with other users in your organization. Just like any other Azure resource, you can use Azure role-based access control (Azure RBAC) to share the template spec. You can use Azure CLI or Azure PowerShell to create template specs by providing Bicep files. The Bicep files are transpiled into ARM JSON templates before they're stored. Currently, you can't import a Bicep file from the Azure portal to create a template spec resource.

Microsoft.Resources/templateSpecs is the resource type for template specs. It consists of a main template and any number of linked templates. Azure securely stores template specs in resource groups. Both the main template and the linked templates must be in JSON. Template Specs support versioning.

To deploy the template spec, you use standard Azure tools like PowerShell, Azure CLI, Azure portal, REST, and other supported SDKs and clients. You use the same commands as you would for the template or the Bicep file.

Note

To use template specs in Bicep with Azure PowerShell, you must install version 6.3.0 or later. To use it with Azure CLI, use version 2.27.0 or later.

When designing your deployment, always consider the lifecycle of the resources and group the resources that share similar lifecycle into a single template spec. For instance, your deployments include multiple instances of Azure Cosmos DB with each instance containing its own databases and containers. Given the databases and the containers don't change much, you want to create one template spec to include a Cosmo DB instance and its underlying databases and containers. You can then use conditional statements in your Bicep along with copy loops to create multiple instances of these resources.

Tip

The choice between module registry and template specs is mostly a matter of preference. There are a few things to consider when you choose between the two:

  • Module registry is only supported by Bicep. If you are not yet using Bicep, use template specs.
  • Content in the Bicep module registry can only be deployed from another Bicep file. Template specs can be deployed directly from the API, Azure PowerShell, Azure CLI, and the Azure portal. You can even use UiFormDefinition to customize the portal deployment experience.
  • Bicep has some limited capabilities for embedding other project artifacts (including non-Bicep and non-ARM-template files. For example, PowerShell scripts, CLI scripts and other binaries) by using the loadTextContent and loadFileAsBase64 functions. Template specs can't package these artifacts.

Training resources

To learn more about template specs, and for hands-on guidance, see Publish libraries of reusable infrastructure code by using template specs.

Required permissions

There are two Azure built-in roles defined for template spec:

In addition, you also need the permissions for deploying a Bicep file. See Deploy - CLI or Deploy - PowerShell.

Why use template specs?

Template specs provide the following benefits:

  • You use standard ARM templates or Bicep files for your template spec.
  • You manage access through Azure RBAC, rather than SAS tokens.
  • Users can deploy the template spec without having write access to the Bicep file.
  • You can integrate the template spec into existing deployment process, such as PowerShell script or DevOps pipeline.

Template specs enable you to create canonical templates and share them with teams in your organization. The template specs are secure because they're available to Azure Resource Manager for deployment, but not accessible to users without the correct permission. Users only need read access to the template spec to deploy its template, so you can share the template without allowing others to modify it.

If you currently have your templates in a GitHub repo or storage account, you run into several challenges when trying to share and use the templates. To deploy the template, you need to either make the template publicly accessible or manage access with SAS tokens. To get around this limitation, users might create local copies, which eventually diverge from your original template. Template specs simplify sharing templates.

The templates you include in a template spec should be verified by administrators in your organization to follow the organization's requirements and guidance.

Create template spec

The following example shows a simple Bicep file for creating a storage account in Azure.

@allowed([
  'Standard_LRS'
  'Standard_GRS'
  'Standard_ZRS'
  'Premium_LRS'
])
param storageAccountType string = 'Standard_LRS'

resource stg 'Microsoft.Storage/storageAccounts@2023-04-01' = {
  name:  'store${uniqueString(resourceGroup().id)}'
  location: resourceGroup().location
  sku: {
    name: storageAccountType
  }
  kind:'StorageV2'
}

Create a template spec by using:

New-AzTemplateSpec -Name storageSpec -Version 1.0a -ResourceGroupName templateSpecsRg -Location westus2 -TemplateFile ./mainTemplate.bicep

You can also create template specs by using Bicep files. However the content of mainTemplate must be in JSON. The following template creates a template spec to deploy a storage account:

param templateSpecName string = 'CreateStorageAccount'
param templateSpecVersionName string = '0.1'
param location string = resourceGroup().location

resource createTemplateSpec 'Microsoft.Resources/templateSpecs@2022-02-01' = {
  name: templateSpecName
  location: location
  properties: {
    description: 'A basic templateSpec - creates a storage account.'
    displayName: 'Storage account (Standard_LRS)'
  }
}

resource createTemplateSpecVersion 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = {
  parent: createTemplateSpec
  name: templateSpecVersionName
  location: location
  properties: {
    mainTemplate: {
      '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
      'contentVersion': '1.0.0.0'
      'parameters': {
        'storageAccountType': {
          'type': 'string'
          'defaultValue': 'Standard_LRS'
          'allowedValues': [
            'Standard_LRS'
            'Standard_GRS'
            'Standard_ZRS'
            'Premium_LRS'
          ]
        }
      }
      'resources': [
        {
          'type': 'Microsoft.Storage/storageAccounts'
          'apiVersion': '2023-04-01'
          'name': 'store$uniquestring(resourceGroup().id)'
          'location': resourceGroup().location
          'kind': 'StorageV2'
          'sku': {
            'name': '[parameters(\'storageAccountType\')]'
          }
        }
      ]
    }
  }
}

The JSON template embedded in the Bicep file needs to make these changes:

  • Remove the commas at the end of the lines.
  • Replace double quotes to single quotes.
  • Escape the single quotes within the expressions. For example, 'name': '[parameters(\'storageAccountType\')]'.
  • To access the parameters and variables defined in the Bicep file, you can directly use the parameter names and the variable names. To access the parameters and variables defined in mainTemplate, you still need to use the ARM JSON template syntax. For example, 'name': '[parameters(\'storageAccountType\')]'.
  • Use the Bicep syntax to call Bicep functions. For example, 'location': resourceGroup().location.

The size of a template spec is limited to approximated 2 MB. If a template spec size exceeds the limit, you get the TemplateSpecTooLarge error code. The error message says:

The size of the template spec content exceeds the maximum limit. For large template specs with many artifacts, the recommended course of action is to split it into multiple template specs and reference them modularly via TemplateLinks.

You can view all template specs in your subscription by using:

Get-AzTemplateSpec

You can view details of a template spec, including its versions with:

Get-AzTemplateSpec -ResourceGroupName templateSpecsRG -Name storageSpec

Deploy template spec

After you've created the template spec, users with the Template Specs Reader role can deploy it. In addition, you also need the permissions for deploying an ARM template. See Deploy - CLI or Deploy - PowerShell.

Template specs can be deployed through the portal, PowerShell, Azure CLI, or as a Bicep module in a larger template deployment. Users in an organization can deploy a template spec to any scope in Azure (resource group, subscription, management group, or tenant).

Instead of passing in a path or URI for a Bicep file, you deploy a template spec by providing its resource ID. The resource ID has the following format:

/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Resources/templateSpecs/{template-spec-name}/versions/{template-spec-version}

Notice that the resource ID includes a version name for the template spec.

For example, you deploy a template spec with the following command.

$id = "/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/templateSpecsRG/providers/Microsoft.Resources/templateSpecs/storageSpec/versions/1.0a"

New-AzResourceGroupDeployment `
  -TemplateSpecId $id `
  -ResourceGroupName demoRG

In practice, you'll typically run Get-AzTemplateSpec or az ts show to get the ID of the template spec you want to deploy.

$id = (Get-AzTemplateSpec -Name storageSpec -ResourceGroupName templateSpecsRg -Version 1.0a).Versions.Id

New-AzResourceGroupDeployment `
  -ResourceGroupName demoRG `
  -TemplateSpecId $id

You can also open a URL in the following format to deploy a template spec:

https://portal.azure.com/#create/Microsoft.Template/templateSpecVersionId/%2fsubscriptions%2f{subscription-id}%2fresourceGroups%2f{resource-group-name}%2fproviders%2fMicrosoft.Resources%2ftemplateSpecs%2f{template-spec-name}%2fversions%2f{template-spec-version}

Parameters

Passing in parameters to template spec is similar to passing parameters to a Bicep file. Add the parameter values either inline or in a parameter file.

Inline parameters

To pass a parameter inline, use:

New-AzResourceGroupDeployment `
  -TemplateSpecId $id `
  -ResourceGroupName demoRG `
  -StorageAccountType Standard_GRS

Parameter files

  • Use Bicep parameters file

    To create a Bicep parameter file, you must specify the using statement. Here's an example:

    using 'using 'ts:<subscription-id>/<resource-group-name>/<template-spec-name>:<tag>'
    
    param StorageAccountType = 'Standard_GRS'
    

    For more information, see Bicep parameters file.

    To pass parameter file with:

    Currently, you can't deploy a template spec with a .bicepparam file by using Azure PowerShell.

  • Use JSON parameters file

    The following JSON is a sample JSON parameters file:

    {
      "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
      "contentVersion": "1.0.0.0",
      "parameters": {
        "StorageAccountType": {
          "value": "Standard_GRS"
        }
      }
    }
    

    And, pass that parameter file with:

    New-AzResourceGroupDeployment `
      -TemplateSpecId $id `
      -ResourceGroupName demoRG `
      -TemplateParameterFile ./mainTemplate.parameters.json
    

Versioning

When you create a template spec, you provide a version name for it. As you iterate on the template code, you can either update an existing version (for hotfixes) or publish a new version. The version is a text string. You can choose to follow any versioning system, including semantic versioning. Users of the template spec can provide the version name they want to use when deploying it. You can have an unlimit number of versions.

Use tags

Tags help you logically organize your resources. You can add tags to template specs by using Azure PowerShell and Azure CLI. The following example shows how to specify tags when creating the template spec:

New-AzTemplateSpec `
  -Name storageSpec `
  -Version 1.0a `
  -ResourceGroupName templateSpecsRg `
  -Location westus2 `
  -TemplateFile ./mainTemplate.bicep `
  -Tag @{Dept="Finance";Environment="Production"}

The next example shows how to apply tags when updating an existing template spec:

Set-AzTemplateSpec `
  -Name storageSpec `
  -Version 1.0a `
  -ResourceGroupName templateSpecsRg `
  -Location westus2 `
  -TemplateFile ./mainTemplate.bicep `
  -Tag @{Dept="Finance";Environment="Production"}

Both the template and its versions can have tags. The tags are applied or inherited depending on the parameters you specify.

Template spec Version Version parameter Tag parameter Tag values
Exists N/A Not specified Specified applied to the template spec
Exists New Specified Not specified inherited from the template spec to the version
New New Specified Specified applied to both template spec and version
Exists New Specified Specified applied to the version
Exists Exists Specified Specified applied to the version

After creating a template spec, you can link to that template spec in a Bicep module. The template spec is deployed when you deploy the Bicep file containing that module. For more information, see File in template spec.

To create aliases for template specs intended for module linking, see Aliases for modules.

Next steps

To learn more about template specs, and for hands-on guidance, see Publish libraries of reusable infrastructure code by using template specs.