0Pricing
Cloud & IT Cert Prep · Lesson

Writing ARM Templates

Build a parameterised ARM template in JSON to deploy a storage account and VM, and use template functions and variables to make templates reusable.

Writing ARM Templates is a free Cloud & IT Cert Prep lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Cloud & IT Cert Prep learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Why Use ARM Templates?

ARM templates let you define Azure infrastructure as code in JSON format. This enables repeatable, consistent deployments that can be version-controlled alongside your application code. Templates are idempotent — running the same template multiple times produces the same result, making them safe to re-apply after changes.

Template Skeleton and Schema

Every ARM template starts with a $schema property pointing to the template schema URL, followed by a contentVersion string. The schema tells the Azure portal and editor extensions how to validate and provide IntelliSense for your template. The five main sections that follow are parameters, variables, functions, resources, and outputs.

{
  '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#',
  'contentVersion': '1.0.0.0',
  'parameters': {},
  'variables': {},
  'functions': [],
  'resources': [],
  'outputs': {}
}

Defining Parameters

Parameters make templates reusable by accepting inputs at deployment time. Each parameter has a type (string, int, bool, object, array, secureString), an optional defaultValue, and optional allowedValues for validation. Using secureString for passwords ensures the value is never logged in deployment history.

"parameters": {
  "storageAccountName": {
    "type": "string",
    "minLength": 3,
    "maxLength": 24,
    "metadata": { "description": "Globally unique storage account name" }
  },
  "sku": {
    "type": "string",
    "defaultValue": "Standard_LRS",
    "allowedValues": ["Standard_LRS", "Standard_GRS", "Premium_LRS"]
  }
}

Using Variables for Computed Values

Variables store values computed from parameters or template functions, reducing repetition and making templates easier to maintain. Variables are evaluated once and referenced throughout the resources section using the [variables('name')] expression. A common pattern is building a resource name by concatenating a parameter with a unique suffix.

"variables": {
  "uniqueStorageName": "[concat(parameters('storageAccountName'), uniqueString(resourceGroup().id))]",
  "location": "[resourceGroup().location]"
}

Defining Resources

The resources array is the heart of an ARM template. Each element describes one Azure resource with mandatory fields: type, apiVersion, name, and location. The apiVersion pins the resource provider schema version — always use a recent stable version to access the latest features and avoid deprecated properties.

"resources": [
  {
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2023-01-01",
    "name": "[variables('uniqueStorageName')]",
    "location": "[variables('location')]",
    "sku": { "name": "[parameters('sku')]" },
    "kind": "StorageV2",
    "properties": {
      "supportsHttpsTrafficOnly": true,
      "minimumTlsVersion": "TLS1_2"
    }
  }
]

Template Functions and Expressions

ARM template expressions are wrapped in square brackets [...] and support built-in functions for strings, arrays, objects, and resource IDs. Common functions include concat(), resourceGroup(), resourceId(), uniqueString(), and parameters(). These functions are evaluated server-side by ARM at deployment time, not locally.

// Reference a resource ID inside a template
"subnetId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', 'myVNet', 'mySubnet')]"

// Build a unique, deterministic name
"name": "[concat('storage', uniqueString(resourceGroup().id))]"

// Conditionally include a resource
"condition": "[equals(parameters('deployStorage'), true)]"

Outputs: Returning Values

The outputs section defines values ARM returns after a successful deployment. Outputs are essential for chaining templates — you deploy a network template and output the subnet resource ID, then pass it as a parameter to a VM template. Outputs can reference any expression, including resource properties from the deployment.

"outputs": {
  "storageAccountName": {
    "type": "string",
    "value": "[variables('uniqueStorageName')]"
  },
  "blobEndpoint": {
    "type": "string",
    "value": "[reference(variables('uniqueStorageName')).primaryEndpoints.blob]"
  }
}

Linked and Nested Templates

For complex architectures, ARM supports linked templates (referencing external template URLs) and nested templates (embedding a template inside the resources array using type Microsoft.Resources/deployments). This lets you break a large infrastructure deployment into modular, reusable pieces while keeping a single orchestration template as the entry point.

{
  "type": "Microsoft.Resources/deployments",
  "apiVersion": "2021-04-01",
  "name": "networkDeploy",
  "properties": {
    "mode": "Incremental",
    "templateLink": {
      "uri": "https://raw.githubusercontent.com/contoso/templates/main/network.json",
      "contentVersion": "1.0.0.0"
    },
    "parameters": {
      "vnetName": { "value": "[parameters('vnetName')]" }
    }
  }
}

Parameters Files

Instead of passing parameters on the command line, store them in a separate parameters file — a JSON file with a parameters object containing name-value pairs. Parameters files can be environment-specific (e.g., dev.parameters.json, prod.parameters.json) and committed to source control, keeping sensitive values in Azure Key Vault references rather than plain text.

// dev.parameters.json
{
  '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#',
  'contentVersion': '1.0.0.0',
  'parameters': {
    'storageAccountName': { 'value': 'devstorageacct' },
    'sku': { 'value': 'Standard_LRS' }
  }
}

// Deploy with parameters file
// az deployment group create -g MyRG -f azuredeploy.json -p dev.parameters.json

Deploying and Validating Templates

Use the Azure CLI command az deployment group create to deploy a template to a resource group. Before deploying to production, run az deployment group validate to catch schema and logic errors, and az deployment group what-if to preview resource changes. These three commands form a safe deployment pipeline: validate, preview, deploy.

# Step 1: Validate the template syntax
az deployment group validate \
  --resource-group MyRG \
  --template-file azuredeploy.json \
  --parameters @dev.parameters.json

# Step 2: Preview changes
az deployment group what-if \
  --resource-group MyRG \
  --template-file azuredeploy.json \
  --parameters @dev.parameters.json

# Step 3: Deploy
az deployment group create \
  --resource-group MyRG \
  --template-file azuredeploy.json \
  --parameters @dev.parameters.json

ARM Template Best Practices

Follow these ARM template best practices: use parameters for environment-specific values, use variables to avoid repetition, pin API versions to stable versions, use secureString for passwords, add metadata descriptions to parameters, and separate large templates into linked modules. Store templates in a Git repository and deploy them through a CI/CD pipeline for auditability.

Quick Check

Test your understanding of Microsoft Azure Fundamentals (AZ-900) concepts from this lesson.

Lesson Recap

In this lesson you learned: ARM templates are JSON documents that declaratively define Azure infrastructure, parameters and variables make templates reusable and maintainable, and the validate, what-if, deploy workflow enables safe, repeatable deployments. Next up we explore Bicep, a modern abstraction over ARM JSON.

Frequently asked questions

Is the “Writing ARM Templates” lesson free?

Yes — the full text of “Writing ARM Templates” is free to read here on the web, and the Cloud & IT Cert Prep course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Cloud & IT Cert Prep course, upgrade to CoddyKit PRO.

What will I learn in “Writing ARM Templates”?

Build a parameterised ARM template in JSON to deploy a storage account and VM, and use template functions and variables to make templates reusable. You practise Cloud & IT Cert Prep with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Cloud & IT Cert Prep?

No prior experience is required. Cloud & IT Cert Prep on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Writing ARM Templates” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Cloud & IT Cert Prep lesson?

Yes. Every Cloud & IT Cert Prep lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. How Azure Resource Manager Works
  2. Writing ARM Templates
  3. Bicep: Modern Azure IaC
  4. Terraform on Azure
← Back to Cloud & IT Cert Prep