Proposed Pull Request Change

title description ms.topic ms.custom ms.date
Define multiple instances of a property Use copy operation in an Azure Resource Manager template (ARM template) to iterate multiple times when creating a property on a resource. how-to devx-track-arm-template 04/28/2025
📄 Document Links
GitHub View on GitHub Microsoft Learn View on Microsoft Learn
Raw New Markdown
Generating updated version of doc...
Rendered New Markdown
Generating updated version of doc...
+0 -0
+0 -0
--- title: Define multiple instances of a property description: Use copy operation in an Azure Resource Manager template (ARM template) to iterate multiple times when creating a property on a resource. ms.topic: how-to ms.custom: devx-track-arm-template ms.date: 04/28/2025 --- # Property iteration in ARM templates This article shows you how to create more than one instance of a property in your Azure Resource Manager template (ARM template). By adding copy loop to the properties section of a resource in your template, you can dynamically set the number of items for a property during deployment. You also avoid having to repeat template syntax. You can only use copy loop with top-level resources, even when applying copy loop to a property. To learn about changing a child resource to a top-level resource, see [Iteration for a child resource](copy-resources.md#iteration-for-a-child-resource). You can also use copy loop with [resources](copy-resources.md), [variables](copy-variables.md), and [outputs](copy-outputs.md). > [!TIP] > We recommend [Bicep](../bicep/overview.md) because it offers the same capabilities as ARM templates and the syntax is easier to use. To learn more, see [loops](../bicep/loops.md). ## Syntax Add the `copy` element to the resources section of your template to set the number of items for a property. The copy element has the following general format: ```json "copy": [ { "name": "<name-of-property>", "count": <number-of-iterations>, "input": <values-for-the-property> } ] ``` For `name`, provide the name of the resource property that you want to create. The `count` property specifies the number of iterations you want for the property. The `input` property specifies the properties that you want to repeat. You create an array of elements constructed from the value in the `input` property. ## Copy limits The count can't exceed 800. The count can't be a negative number. It can be zero if you deploy the template with a recent version of Azure CLI, PowerShell, or REST API. Specifically, you must use: - Azure PowerShell **2.6** or later - Azure CLI **2.0.74** or later - REST API version **2019-05-10** or later - [Linked deployments](linked-templates.md) must use API version **2019-05-10** or later for the deployment resource type Earlier versions of PowerShell, CLI, and the REST API don't support zero for count. ## Property iteration The following example shows how to apply copy loop to the `dataDisks` property on a virtual machine: ```json { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "numberOfDataDisks": { "type": "int", "minValue": 0, "maxValue": 16, "defaultValue": 3, "metadata": { "description": "The number of dataDisks to create." } }, ... }, "resources": [ { "type": "Microsoft.Compute/virtualMachines", "apiVersion": "2025-04-01", ... "properties": { "storageProfile": { ... "copy": [ { "name": "dataDisks", "count": "[parameters('numberOfDataDisks')]", "input": { "lun": "[copyIndex('dataDisks')]", "createOption": "Empty", "diskSizeGB": 1023 } } ] } ... } } ] } ``` Notice that when using [copyIndex](template-functions-numeric.md#copyindex) inside a property iteration, you must provide the name of the iteration. Property iteration also supports an offset argument. The offset must come after the name of the iteration, such as `copyIndex('dataDisks', 1)`. The deployed template becomes: ```json { "name": "examplevm", "type": "Microsoft.Compute/virtualMachines", "apiVersion": "2025-04-01", "properties": { "storageProfile": { "dataDisks": [ { "lun": 0, "createOption": "Empty", "diskSizeGB": 1023 }, { "lun": 1, "createOption": "Empty", "diskSizeGB": 1023 }, { "lun": 2, "createOption": "Empty", "diskSizeGB": 1023 } ], ... ``` The copy operation is helpful when working with arrays because you can iterate through each element in the array. Use the [length](template-functions-array.md#length) function on the array to specify the count for iterations, and `copyIndex` to retrieve the current index in the array. The following example template creates a failover group for databases that are passed in as an array. ```json { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "primaryServerName": { "type": "string" }, "secondaryServerName": { "type": "string" }, "databaseNames": { "type": "array", "defaultValue": [ "mydb1", "mydb2", "mydb3" ] } }, "variables": { "failoverName": "[format('{0}/{1}failovergroups', parameters('primaryServerName'), parameters('primaryServerName'))]" }, "resources": [ { "type": "Microsoft.Sql/servers/failoverGroups", "apiVersion": "2015-05-01-preview", "name": "[variables('failoverName')]", "properties": { "readWriteEndpoint": { "failoverPolicy": "Automatic", "failoverWithDataLossGracePeriodMinutes": 60 }, "readOnlyEndpoint": { "failoverPolicy": "Disabled" }, "partnerServers": [ { "id": "[resourceId('Microsoft.Sql/servers', parameters('secondaryServerName'))]" } ], "copy": [ { "name": "databases", "count": "[length(parameters('databaseNames'))]", "input": "[resourceId('Microsoft.Sql/servers/databases', parameters('primaryServerName'), parameters('databaseNames')[copyIndex('databases')])]" } ] } } ], "outputs": { } } ``` The `copy` element is an array so you can specify more than one property for the resource. ```json { "type": "Microsoft.Network/loadBalancers", "apiVersion": "2025-01-01", "name": "exampleLB", "properties": { "copy": [ { "name": "loadBalancingRules", "count": "[length(parameters('loadBalancingRules'))]", "input": { ... } }, { "name": "probes", "count": "[length(parameters('loadBalancingRules'))]", "input": { ... } } ] } } ``` You can use resource and property iterations together. Reference the property iteration by name. ```json { "type": "Microsoft.Network/virtualNetworks", "apiVersion": "2025-01-01", "name": "[format('{0}{1}', parameters('vnetname'), copyIndex())]", "copy":{ "count": 2, "name": "vnetloop" }, "location": "[resourceGroup().location]", "properties": { "addressSpace": { "addressPrefixes": [ "[parameters('addressPrefix')]" ] }, "copy": [ { "name": "subnets", "count": 2, "input": { "name": "[format('subnet-{0}', copyIndex('subnets'))]", "properties": { "addressPrefix": "[variables('subnetAddressPrefix')[copyIndex('subnets')]]" } } } ] } } ``` ## Example templates The following example shows a common scenario for creating more than one value for a property. |Template |Description | |---------|---------| |[VM deployment with a variable number of data disks](https://github.com/Azure/azure-quickstart-templates/tree/master/quickstarts/microsoft.compute/vm-windows-copy-datadisks) |Deploys several data disks with a virtual machine. | ## Next steps - To go through a tutorial, see [Tutorial: Create multiple resource instances with ARM templates](template-tutorial-create-multiple-instances.md). - For other uses of the copy loop, see: - [Resource iteration in ARM templates](copy-resources.md) - [Variable iteration in ARM templates](copy-variables.md) - [Output iteration in ARM templates](copy-outputs.md) - If you want to learn about the sections of a template, see [Understand the structure and syntax of ARM templates](./syntax.md). - To learn how to deploy your template, see [Deploy resources with ARM templates and Azure PowerShell](deploy-powershell.md).
Success! Branch created successfully. Create Pull Request on GitHub
Error: