The Joy of Tags

Maybe joy is not the right word, but tags can be a handy tool for organising and querying your Azure resources, and are something I find are often not used very well. In this article, we'll take a look at why tags are useful and some examples of how you can use them and what you can do to ensure they are applied.


If you've not already seen them, tags allow you to add arbitrary key-value pairs to most (there are still some edge cases) resource in Azure. You can use pretty much any free text in both the label and the value.


Tags are pretty versatile, and there are lots of different things they can be used for, but I wanted to highlight some of the most useful ones I use regularly.

Resource Metadata

Metadata is the most apparent use for tags, to store some information about the resource, or resources. When you deploy a resource into Azure, you get with it many items of metadata about the resource - location, size, SKU etc. This information is all about the resource itself, but often you want to be able to store information that is more focused around your business process, billing information or application specific information. None of this data can be cleaned from the standard resource metadata, so we need to add it using tags. This way, other people (or you when you inevitably forget) who come across the resource can get this information quickly and easily. Some common examples of metadata stored in tags include:

  • Owner information - who is responsible for the resource and should be contacted in the event of issues
  • Billing Information - who is responsible for paying for the resource, and where the cost should be allocated. This often includes things like internal cost codes
  • Application Information - often when deploying an application into Azure it is made up of lots of different components, which may not all be stored in the same resource group. Tagging these resources with the application name or code allows for quickly seeing which application a resource is servicing
  • Environment type - indicating whether resources are for development, test, production etc.
  • Deployment information - information about who deployed the resource and when. This data is stored in the activity log but will age out after 90 days. Storing it in a tag makes it easy to see and have it permanently tied to the resource
  • SLA Information - For your internal support teams to see what tier of support and SLA a resource has

Grouping, Searching and Reporting

As well as containing metadata about resources, tags can be used to tie resources with the same metadata together and allow us to query for resources with that metadata.

Resource Lists

If you look in the Azure portal all the resource listing pages if a drop down that allows you to filter resources by a specific tag or set of tags, this makes it really easy to get a list of resources that belong to a specific application, have been created by a specific user, or that have a particular SLA.


This filtering also extends into the CLI and PowerShell, where nearly every command allows you to specify tags and values to query by. Both the examples below query all Azure resources for those with the tag of "application" set to "".


 Get-AzResource -Tag @{ application="" }


az resource list --tag application=""

Resource Explorer

If you're using Azure Resource Explorer to find out more about your deployed resources (see here for how to do this), you can scope your queries to specific tags. For example, if we want to see what regions are in use by a specific application we can use the "application" tag we created to filter our resource graph query:

az graph query -q "where tags.application=~'' |summarize count() by location | project total=count_, location | order by total desc " --output table

This command returns a table of all regions that are in use by applications with the "" name


Cost Management

One of the common uses of tags is for cost management and billing. Azure Cost management allows you to query resources by tag so that you can break down your Azure spend by any tag value. This makes it easy to see costs broken down by things like applications, users, environment type etc. If you are doing internal cross-charging for Azure spend, then it is also easy to assign a cost code as a tag and get a quick cost breakdown by code.



This is really extending the tasks above, but one great use of tags is to provide information for automation. For example, a common requirement in Azure is to turn VMs on and off at certain times. You can turn them off using the DevTest Labs functionality, but that has limited functionality and can't be used to turn them back on. Instead, one approach a colleague of mine implemented was to use Azure Automation to do the work of turning machines on and off and use tags to store the data about the operation. In his solution he had 3 tags which stored data on:

  1. Whether the machine should be turned off/on by the automation
  2. What times the machine should be turned on (and so imply when it should be turned off)
  3. What time zone the times on the second tag refer to

When the automation script ran, it could quickly get a list of all machines with the tag indicating they should be turned off or on, and then evaluate the time tags to determine if it is time to turn them off or on.

Another use could be around alert automation. When you configure alerts in Azure Monitor or Log Analytics, you can have these alerts trigger an Azure Automation Run Book, or Azure Function to do some remediation. We can use tags to determine what remediation is undertaken. For example, we can use the "environment" tag, which indicates if resources are in a dev, test or production environment, in our automation to decide on an action to take. If we get a memory alert then if the resource is dev or test, we reboot it, but if it is production, we won't take any action other than sending a notification.

Enforcing Tag Use

So hopefully you can see how versatile tags can be and where you can use them. However, these are no use if your resources are not tagged properly, and it is very easy to not apply tags, or perhaps worse apply tags that are misspelt or have the wrong values. So how do we ensure that tags are applied and are correct?

Resource Groups

A straightforward approach is to apply tags at the resource group level manually and then push these tags down to all resource in the resource group. Unfortunately, there isn't a way to force this to happen by default; there is no inheritance for tags, so we need to do this using a script. You can find an example of doing this via PowerShell on Github here. This could then be run manually or regularly using Azure Automation.

You can also use a policy to enforce tags from a resource group onto child resources. An example can be found here.

ARM Templates

Using ARM templates to apply tags is pretty straight forward, you pass through a list of tag names and values at the top level of any resource, for example on a storage account:

    "apiVersion": "2016-01-01",
    "type": "Microsoft.Storage/storageAccounts",
    "name": "[concat('storage', uniqueString(resourceGroup().id))]",
    "location": "[resourceGroup().location]",
    "tags": {
        "Dept": "Finance",
        "Environment": "Production"
    "sku": {
        "name": "Standard_LRS"
    "kind": "Storage",
    "properties": {}

To make things more consistent, you could also look at using template nesting to provide a pre-filled list of tags to apply which user can import into their main template and then use to get the list of tags for their resources.


Azure policy can enforce tag usage, and there are few ways you can do this:

  1. Create a policy that specifies both a list of tags that are required and the values for these tags. This will ensure that even if tags are not specified when a resource is created, the policy will add them. While this approach ensures tags are applied you lose flexibility on the values used, as these are defined at the time you apply the policy, the user cannot change them. An example can be seen here.
  2. Create a policy that requires certain tags to be applied, but do not enforce a value. If the tag is not set the deployment will fail. This allows more flexibility, as the user can set the value, but if they are not set, then the deployment will fail.
  3. Create a policy that requires a certain tag be applied, and specify a default value if it is not applied. This is a middle ground between the other two options. Example here.

The policies mentioned above will enforce the application of tags, but one thing you also need to be careful of is that the value of the tag is in the correct format. You can also use policies to define a pattern that the tag must match. This can be used to ensure, for example, that a tag value for a contact is always in email format. An example can be found here.


While tagging is pretty versatile, there are a few issues to be aware of:

Tag Limit

You are limited to 15 tags per resource. This may sound like a reasonable amount, but you also need to bear in mind that some resources will get tags applied by the Azure fabric as well, which take up part of this number. For example, AKS applies several tags to resources it creates.


It is not possible to tag subscriptions. If you want to store information about a subscription in tags you would need to create a proxy resource group in the sub that will hold this information and tag that.

Image Attribution

Labels for Art vs Craft Show flickr photo by Allspire shared under a Creative Commons (BY-SA) license