Using linked and nested templates when deploying Azure resources

04/29/2020

13 minutes to read

In this article

To deploy complex solutions, you can break your template into many related templates, and then deploy them together through a main template. The related templates can be separate files or template syntax that is embedded within the main template. This article uses the term linked template to refer to a separate template file that is referenced via a link from the main template. It uses the term nested template to refer to embedded template syntax within the main template.

For small to medium solutions, a single template is easier to understand and maintain. You can see all the resources and values in a single file. For advanced scenarios, linked templates enable you to break down the solution into targeted components. You can easily reuse these templates for other scenarios.

Expression evaluation scope in nested templates

When using a nested template, you can specify whether template expressions are evaluated within the scope of the parent template or the nested template. The scope determines how parameters, variables, and functions like resourceGroup and subscription are resolved.

You set the scope through the expressionEvaluationOptions property. By default, the expressionEvaluationOptions property is set to outer, which means it uses the parent template scope. Set the value to inner to cause expressions to be evaluated within the scope of the nested template.

The following template demonstrates how template expressions are resolved according to the scope. It contains a variable named exampleVar that is defined in both the parent template and the nested template. It returns the value of the variable.

The value of exampleVar changes depending on the value of the scope property in expressionEvaluationOptions. The following table shows the results for both scopes.

expressionEvaluationOptionsscope

Output

inner

from nested template

outer (or default)

from parent template

The following example deploys a SQL server and retrieves a key vault secret to use for the password. The scope is set to inner because it dynamically creates the key vault ID (see adminPassword.reference.keyVault in the outer templates parameters) and passes it as a parameter to the nested template.

When scope is set to outer, you can't use the reference function in the outputs section of a nested template for a resource you have deployed in the nested template. To return the values for a deployed resource in a nested template, either use inner scope or convert your nested template to a linked template.

Linked template

To link a template, add a deployments resource to your main template. In the templateLink property, specify the URI of the template to include. The following example links to a template that deploys a new storage account.

When referencing a linked template, the value of uri must not be a local file or a file that is only available on your local network. You must provide a URI value that downloadable as http or https.

Note

You may reference templates using parameters that ultimately resolve
to something that uses http or https, for example, using the
_artifactsLocation parameter like so:
"uri": "[concat(parameters('_artifactsLocation'), '/shared/os-disk-parts-md.json', parameters('_artifactsLocationSasToken'))]",

Resource Manager must be able to access the template. One option is to place your linked template in a storage account, and use the URI for that item.

Parameters for linked template

You can provide the parameters for your linked template either in an external file or inline. When providing an external parameter file, use the parametersLink property:

You can't use both inline parameters and a link to a parameter file. The deployment fails with an error when both parametersLink and parameters are specified.

contentVersion

You don't have to provide the contentVersion property for the templateLink or parametersLink property. If you don't provide a contentVersion, the current version of the template is deployed. If you provide a value for content version, it must match the version in the linked template; otherwise, the deployment fails with an error.

Using variables to link templates

The previous examples showed hard-coded URL values for the template links. This approach might work for a simple template, but it doesn't work well for a large set of modular templates. Instead, you can create a static variable that stores a base URL for the main template and then dynamically create URLs for the linked templates from that base URL. The benefit of this approach is that you can easily move or fork the template because you need to change only the static variable in the main template. The main template passes the correct URIs throughout the decomposed template.

The following example shows how to use a base URL to create two URLs for linked templates (sharedTemplateUrl and vmTemplate).

You can also use deployment() to get the base URL for the current template, and use that to get the URL for other templates in the same location. This approach is useful if your template location changes or you want to avoid hard coding URLs in the template file. The templateLink property is only returned when linking to a remote template with a URL. If you're using a local template, that property isn't available.

Using copy

To create multiple instances of a resource with a nested template, add the copy element at the level of the Microsoft.Resources/deployments resource. Or, if the scope is inner, you can add the copy within the nested template.

The following example template shows how to use copy with a nested template.

The main template deploys the linked template and gets the returned value. Notice that it references the deployment resource by name, and it uses the name of the property returned by the linked template.

As with other resource types, you can set dependencies between the linked template and other resources. When other resources require an output value from the linked template, make sure the linked template is deployed before them. Or, when the linked template relies on other resources, make sure other resources are deployed before the linked template.

The following example shows a template that deploys a public IP address and returns the resource ID of the Azure resource for that public IP:

To use the public IP address from the preceding template when deploying a load balancer, link to the template and declare a dependency on the Microsoft.Resources/deployments resource. The public IP address on the load balancer is set to the output value from the linked template.

Securing an external template

Although the linked template must be externally available, it doesn't need to be generally available to the public. You can add your template to a private storage account that is accessible to only the storage account owner. Then, you create a shared access signature (SAS) token to enable access during deployment. You add that SAS token to the URI for the linked template. Even though the token is passed in as a secure string, the URI of the linked template, including the SAS token, is logged in the deployment operations. To limit exposure, set an expiration for the token.

In PowerShell, you get a token for the container and deploy the templates with the following commands. Notice that the containerSasToken parameter is defined in the template. It isn't a parameter in the New-AzResourceGroupDeployment command.