[CODE] Understand ARM Template Structure

Keine Kommentare zu [CODE] Understand ARM Template Structure

As we have discussed in the last [CODE] post, it is pretty awesome to work with Azure Resource Manager Templates. But besides downloading or exporting them, it is also important to understand the ARM Template Structure. Having this, you will be able to read and understand what a Template will do.

ARM Template Structure

It is the same as with PowerShell: It is easy to copy and paste scripts. But to really understand what they are doing, you must „read“ them. Just think about all the bad things (or in Azure expensive things) that could be included without your notice.

ARM Template Structure

As already mentioned ARM templates are written in a JSON notation. So you will have a lot of fun with brackets and commas. An empty template looks like this:

  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "",
  "apiProfile": "",
  "parameters": {  },
  "variables": {  },
  "functions": [  ],
  "resources": [  ],
  "outputs": {  }

Out of the existing elements there are only three of them required:

  • Schema
  • ContentVersion
  • Resources

This is the minimum you have to bring in, to successfully deploy a template to Azure. But let me explain the parts a bit more in detail.


The schema is defining the location of the JSON schema file that describes the version of the template language. It will be used for features like intellisense in your editing tool.

Right now there are two different Schemas available:

  • For resource group deployments, use: https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#
  • For subscription deployments, use: https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#


The ContentVersion can be used to track Versions of your Template. If you are managing your ARM Templates in a code repository, this is not really required, as you may have auto-versioning.

But if you have multiple versions of a Template, with significant differences, you can use this value during deployment to make sure you are executing the correct template.


Every Azure Resource Provider has different API Versions available. This depends on the features present and what you can do with it. Sometimes you want to control a specific feature that is only available in a newer API version.

Or if you are using Azure and Azure Stack and you want to deploy your applications consistently between both, you have to make sure, that both do support the same API.

In most cases you will find the apiVersion defined for a specific Resource in the Template:

  "resources": [
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2016-01-01",

With the apiProfile on top level you do not have to define the apiVersion for every resource, as they will refer to the profile instead.


These are values that will be defined during deployment. So you will use parameters to create re-usable templates. For example, when creating a VM from ARM Template, you can include

  • VM-Name
  • Admin-Name
  • Admin-Password

as Parameters. So you can use this template to create different VMs with different users.

Every Parameter needs a Name and a Type. Additionally you can also define Default Values, Allowed Values, Min or MaxValues and so on.

"parameters": {
  "DEMO-Param" : {
    "type" : "string",
    "defaultValue": "DEMO",
    "allowedValues": [ "<array-of-allowed-values>" ],
    "minLength": <minimum-length-for-string-or-array>,
    "maxLength": <maximum-length-for-string-or-array-parameters>,
    "metadata": {
      "description": "<description-of-the parameter>"


I have seen a lot people struggling with Variables in Templates. Many think of variables as something you can set during deployment. If you are used to PowerShell you may have less problems, as we have Param there too for input Values during execution.

But no matter how, Variables are used to:

  • construct values to be used
  • separate complex expression out of resource code
  • keep static values that are multi-used
  • separate static values to keep overview

As an example you could think of this:

"variables": {
  "NICName": "[concat(parameters('VMName'),'-NIC01')]"

to create a consistent naming of NICs.


Within your template, you can create your own functions. These functions are available for use in your template. Typically, you define complicated expressions that you don’t want to repeat throughout your template. You create the user-defined functions from expressions and functions that are supported in templates.

For example you could create functions to create unique names for resources. many times people solve those topics with Variables already.


That is the heart of the ARM Template Structure. Here you define your resources that should be created or updated in your Resource Group or Subscription.

"resources": [
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2016-01-01",
      "name": "mystorageaccount",
      "location": "[parameters('location')]",
      "properties": {
        "accountType": "Standard_LRS"


Last but not least you can have an output for your Template Deployment. For example if you create a Public IP then you do not know the IP Address until it is created. So you cannot define it upfront. You need to get the Resource ID to use it for a later query towards the IP

So after deployment you can receive the ID back as an output.

"outputs": {
  "resourceID": {
    "type": "string",
    "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('PIPName'))]"

Happy ARMing 🙂

Dieser Post ist auch verfügbar auf: Englisch

Related Posts

Leave a comment

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.

Back to Top