Business Challenge
The confusion is reasonable. They are both key-value pairs, both attach to resources, and the console puts them near each other. Then four things happen that make no sense until you know they are unrelated systems.
cost-centre tag to that VM"
You cannot, not directly. The tag key and the tag value must both be defined before a tag can be attached to a resource. A tag key is a resource created under an organization or a project; each permitted value is another resource created under that key. Only then can a binding attach one to a VM. There is no equivalent of typing a new key on the spot — that is what a label is.
Correct approachDecide up front which of the two a given piece of metadata is. Anything ad-hoc, high-cardinality or team-owned is a label. Anything policy will read is a tag, and it needs designing before it needs applying.
env=prod, so write a policy on that"
Labels cannot be used to set conditions on policies. No amount of labelling discipline produces an enforceable control, because the policy engines do not read labels at all. A label is descriptive; it is forwarded to billing and it is searchable, and that is the extent of its power.
Correct approachIf a value needs to gate access, it is a tag from the beginning. Re-tagging an estate that was labelled for three years is the expensive version of this decision.
Not until everything below it is gone. All the associated bindings must be removed from resources first; once all tag values associated with a key have been deleted, you can then delete the key. A tag is a small dependency tree, not an attribute, and it unwinds in one direction only.
Correct approachTreat tag retirement as a migration with three phases — unbind, delete values, delete key — and script it. A label, by contrast, is removed by editing the resource, and nothing else is affected.
team=platform and nobody tagged it"
Inheritance. When a tag value is attached to a resource, by default all descendants of that resource inherit the same value — so a tag set once on a folder appears on every project and resource beneath it. Labels do not do this; a label exists only on the resource that carries it.
Correct approach
Read tags.inherited in the billing export, which indicates whether a binding is inherited or direct. It is the field that turns "who set this" from an argument into a query.
Architecture
The single most useful sentence about these two systems is that a label is metadata on a resource and a tag is a resource. Everything else follows from that.
The two systems, side by side
| Label | Tag | |
|---|---|---|
| What it is | A key-value pair you assign to a resource. Metadata, nothing more. | Tag keys, tag values and tag bindings are all discrete resources. |
| Created | By typing it on the resource. No prerequisite. | Key and value must be defined before a tag can be attached. |
| Where defined | On each resource, independently. | Under an organization or a project. |
| Inheritance | None. It exists where it was set. | All descendants inherit an attached value by default; a descendant can override it with the same key. |
| Policy | Cannot be used to set conditions on policies. | Read by IAM conditions, Organization Policy and VPC firewall policies. |
| Own IAM | No. Editing a label is editing the resource. | Yes — Tag Viewer, Tag User, Tag Administrator. |
| Billing export | labels, plus project.labels and system_labels. |
tags, with key, value, namespace and inherited. |
Tags have their own access control, and that is the point
Because a tag is a resource, it comes with roles of its own: Tag Viewer (roles/resourcemanager.tagViewer) to see them, Tag User (roles/resourcemanager.tagUser) to attach and remove them, and Tag Administrator (roles/resourcemanager.tagAdmin) to create, update and delete the definitions.
That separation is what makes a tag trustworthy enough to gate access on. If attaching env=prod were merely editing a field on a VM, then anyone who could edit the VM could grant themselves whatever the tag unlocks. Splitting "may attach this tag" from "may edit this resource" is the whole reason the mechanism can carry a security decision, and it is the reason it is heavier than a label.
A tag key's short name is only unique within the organization or project that defines it. The fully qualified form prefixes the namespace — which the billing export documents as representing the resource hierarchy that defines the tag key and values, combinable with the short names to produce a globally unique name. It is why an IAM condition is written as resource.matchTag('123456789012/env', 'prod') rather than just env: the numeric prefix is the organization that owns the definition, and without it the expression would be ambiguous.
Limits, and what they tell you about intent
| Limit | Label | Tag |
|---|---|---|
| Per resource | Up to 64 labels. | A maximum of 50 key-value pairs attached. |
| Definitions available | Unbounded — there is nothing to define. | A maximum of 1000 tag keys within an organization or within a project, raisable on request. |
| Values per key | Any string within the rules. | Up to 1000 predefined values per key by default. |
| Key rules | 1 to 63 characters, cannot be empty, must start with a lowercase letter or international character. | Defined once as a resource and referenced thereafter. |
| Value rules | Can be empty, maximum 63 characters. | Exactly one value per key can be attached to a resource at any given time. |
| Character set | Lowercase letters, numerics, underscores and dashes only. | Set at definition time. |
The shape of those numbers is the design brief. Labels are cheap, numerous and unconstrained because they describe; tags are capped at a thousand keys per organization because they are meant to be a small, governed vocabulary that policies are written against. A tagging scheme that needs more than a thousand keys is a labelling scheme wearing the wrong hat.
Many services let you attach tags to their resources. Far fewer can make a decision based on one. The policy engines that read tags are Identity and Access Management, the Organization Policy Service, and Virtual Private Cloud for network firewall policies — and Google states directly that resources not listed as explicitly supported by policy engine services cannot be targeted directly for conditional enforcement of policies. So a tag can sit on a resource, appear in your billing export, look entirely correct, and still be unable to deny anything on that resource. Check the second list, not the first, before designing a control around it.
Why This Architecture Holds Up
In practice the decision is made once per piece of metadata, and almost always correctly answered by a single question: does anything need to act on this, or only to report on it?
Both reach the billing export — differently
This is the part most often got wrong, including in the closing line of the previous post in this series, which said only one of the two reaches billing. Both do. Information about labels is forwarded to the billing system so that billed charges can be broken down by label, and the standard usage cost export carries labels, project.labels and system_labels. Tags arrived later — the first full month of data with tags is October 2022 — and land in a tags struct with key, value, namespace and inherited.
The difference that matters for cost work is not presence but provenance. A label in the export was set on that resource by someone. A tag in the export may have been set three levels up the hierarchy, and tags.inherited is the field that tells you which. For a chargeback model that is a significant advantage: you can attribute an entire folder's spend from one binding, and still distinguish the resources that were deliberately tagged from the ones that merely inherited.
Will a policy read it? If yes, it is a tag, and it must be defined before anything can carry it. Does it need to apply to a whole branch of the hierarchy at once? If yes, it is a tag, because inheritance is the only mechanism that does that. Everything else — owner, ticket reference, application name, anything with hundreds of distinct values, anything a team invents this week — is a label.
Where each one breaks down
- Labels used for governance. The failure is silent: the labels are all present and correct, and nothing enforces them. Discovered when somebody asks how the control is implemented and the answer is a convention.
- Tags used for description. The failure is friction. Every new value needs a definition created by someone holding Tag Administrator, so the vocabulary either ossifies or the role gets handed out widely, which defeats the separation that made tags worth using.
- Either one used for both. Workable, and the usual outcome is the tag vocabulary slowly filling with descriptive keys nobody writes policy against, until the thousand-key limit becomes a real conversation.
Inheritance is a commitment, not a convenience
Attaching a tag high in the hierarchy is the most efficient thing you can do with one and the easiest to regret. Every descendant inherits it by default, including resources created afterwards by people who have never heard of the tag, and every policy written against it applies to them the moment they exist.
That is exactly what you want for something like environment=production on a folder. It is exactly what you do not want for anything provisional. The override is available — a descendant can bind a different value using the same key — but relying on overrides means the effective value of a tag is a hierarchy walk rather than a fact, and the number of people who will reason about that correctly at three in the morning is small.
Key Architecture Decisions
| Decision | Choose this | Because |
|---|---|---|
| Metadata a policy will read | Tag, designed before applied | Labels cannot be used to set conditions on policies. |
| Metadata only reports read | Label | No definition step, no governed vocabulary, and it still reaches billing. |
| Applying a value to a whole branch | Tag on the folder | All descendants inherit an attached value by default; labels have no inheritance. |
| High-cardinality values | Label | Predefined tag values default to 1000 per key; a label value is any conforming string. |
| Before designing a tag-based control | Check the policy engine list, not the attachment list | Resources not listed as supported by policy engines cannot be targeted for conditional enforcement. |
| Who may attach a governing tag | Tag User, granted narrowly | Separating attachment from resource edit is what lets a tag carry a security decision. |
| Who may define the vocabulary | Tag Administrator, granted very narrowly | It creates, updates and deletes the definitions every policy is written against. |
| Retiring a tag | Unbind, delete values, then delete the key | The key cannot be deleted until its values are, and those cannot go while bindings exist. |
| Chargeback attribution | Tags, and read tags.inherited |
One binding attributes a whole branch, and the field distinguishes deliberate from inherited. |
| Writing an IAM condition | Fully qualified, with the namespace | A short name is unique only within its defining organization or project. |
| A tag vocabulary approaching 1000 keys | Treat it as a design smell | The cap is per organization or project, and describes intent: a small governed set, not an inventory. |
Closing Thought
The reason these two get conflated is that Google gave them the same shape. A key, a value, a resource to stick them on. If they had been called annotations and attributes, or given visibly different syntax, nobody would spend a year labelling an estate for a governance requirement that labels cannot meet.
The distinction worth carrying is not a list of differences but a question about direction. A label is something you write about a resource, and it flows outward to the people reading reports. A tag is something the platform reads from a resource, and it flows inward to the engines deciding what may happen. Metadata that describes, versus metadata that decides. Once a piece of information is on the wrong side of that line, moving it is not an edit — it is a migration with a definition step, an IAM model and a deletion order.
#18 stays with metadata and asks the harder question: resource naming standards that survive three years — what a name has to encode, what it must not, and why the fields people most want in a name are the ones that change.
Comments