Kubernetes Labels vs Annotations: Key Differences

Compare Kubernetes labels and annotations: what each field is for, how selectors treat them, value limits, and when to use labels for grouping versus annotations for descriptive metadata.

Published

Updated

Read time 7 min read

Reviewed byDeepak Prasad

Kubernetes labels and annotations compared on Deployment metadata
Tested on Rocky Linux 10.2 (Red Quartz) workstation
Package kubectl 1.36.3
Applies to Any host with kubectl configured; any Kubernetes cluster
Cert prep CKAD · CKA · CKS
Lab environment Multi-node kubeadm cluster with containerd — install Kubernetes with kubeadm
Privilege Normal user (no sudo required on the workstation)
Scope Labels versus annotations: purpose, comparison table, YAML placement, selector behavior, and when to use each. Does not teach kubectl label, kubectl annotate, matchLabels, or selector troubleshooting — those live in the linked tutorials.
Related guides Kubernetes labels and selectors
Kubernetes annotations
Kubernetes pods
kubectl commands and YAML examples

Kubernetes stores two kinds of user-defined metadata on most objects: labels in metadata.labels and annotations in metadata.annotations. They sit beside each other in YAML, but Kubernetes treats them differently. Labels identify and group resources for selectors; annotations describe resources without participating in selection.

This page is a comparison only. For hands-on work, use the labels and annotations guides listed in Related guides above.


Quick answer

Labels Annotations
YAML field metadata.labels metadata.annotations
Primary purpose Identify and group objects Describe objects for people or tools
Used by selectors? Yes No
Typical value size Short (≤ 63 characters) Long strings, URLs, JSON (≤ 256 KiB total per object)
Example use app=web, environment=production example.com/git-commit=a1b2c3d4

If Kubernetes or kubectl get -l must match the value, use a label. If the value is informational and should not drive routing, ownership, or filtering, use an annotation.


Basic difference

Labels answer: Which group does this object belong to? Services, Deployments, ReplicaSets, and kubectl get -l read labels to find related Pods and controllers. Labels used by controller or Service selectors should remain stable; other labels, such as app.kubernetes.io/version, can change between releases.

Annotations answer: What extra context describes this object? Runbook URLs, owner contacts, tool-specific JSON, and release metadata that should not drive selection live here. Git commits and build IDs can also appear as labels — for example app.kubernetes.io/version — when users or tools need to filter by them. Selectors ignore annotations. Some controllers read specific annotation keys they document (for example Ingress controllers), but that is not the general label-selector mechanism.

Both use optional DNS-style key prefixes (example.com/owner). Neither replaces object names, and neither should store secrets.


Labels and annotations compared

Aspect Labels Annotations
Map location metadata.labels metadata.annotations
Selector participation Matched by kubectl -l, Service spec.selector, controller spec.selector, NetworkPolicy label selectors Not matched by standard label selectors
Value length Name and value portions follow label character and length rules; values at most 63 characters or empty Arbitrary strings; combined keys and values at most 256 KiB per object
Typical consumers Scheduler (via node labels), Services, controllers, kubectl filters Humans, CI/CD, GitOps, optional controller hooks
Changes over time Labels used by controller or Service selectors should remain stable. Other labels, such as app.kubernetes.io/version, can change between releases. Changing selector keys on Pods can break ownership Annotation changes do not affect standard label selectors. However, a controller may react when one of its documented annotation keys changes
Pod template on controllers spec.template.metadata.labels stamps every new Pod spec.template.metadata.annotations stamps every new Pod when needed

Labels and annotations are independent maps. The same object can carry both without conflict.


Side-by-side on one Deployment

The same Deployment can carry identifying labels and descriptive annotations at once. They serve different roles:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  labels:
    app: web
    environment: production
    tier: frontend
  annotations:
    example.com/owner: platform-team
    example.com/git-commit: a1b2c3d4
    example.com/documentation: https://docs.example.com/web
spec:
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
        environment: production
        tier: frontend
    spec:
      containers:
        - name: nginx
          image: nginx:1.27-alpine
  • Labels on the Deployment and Pod template — app, environment, tier — are what selectors and kubectl get -l environment=production can match.
  • Annotations on the Deployment — owner, Git commit, documentation URL — describe the release. They do not appear in spec.selector and are not queried with -l.

To propagate annotations onto every Pod, add them under spec.template.metadata.annotations in the same manifest. Pod-template placement is covered in the Kubernetes annotations guide linked in Related guides.


Wrong vs right choices

Git commit and build ID metadata can be a label or an annotation depending on whether selection matters. Kubernetes documents app.kubernetes.io/version for a revision hash when tools or users need to filter by it.

Metadata Use a label when Use an annotation when
Git commit or build ID You need to filter, select, or group resources by that value and it satisfies label syntax It is only traceability metadata and should not participate in selection

Other metadata types have a clearer split:

Metadata Wrong (label) Right (annotation) Why
Documentation URL metadata.labels.docs: https://... metadata.annotations.example.com/documentation: https://... URLs are long and not meant for kubectl get -l
Application name for Service routing metadata.annotations.app: web only metadata.labels.app: web on the Pod template Services match labels on Pods, not annotations
Environment for filtering metadata.annotations.environment: production only metadata.labels.environment: production kubectl get pods -l environment=production reads labels

Putting selectable data only in annotations is a common mistake: the object looks documented in kubectl describe, but Services and kubectl get -l behave as if that key does not exist. Changing ordinary informational labels is valid; the risk applies mainly when that label participates in workload ownership, routing, policy, or another selector.


When to use labels

Use labels when the value must identify or group objects:

  • Application identity — app, app.kubernetes.io/name
  • Version or revision when selectable — app.kubernetes.io/version for a Git or build identifier tools must filter on
  • Environment or tier for filters — environment=production, tier=frontend
  • Controller ownership — keys in spec.selector.matchLabels and matching Pod-template labels
  • Service endpoints — keys in Service spec.selector that Pods must carry
  • Node selection — node labels read by nodeSelector or affinity (label the node first)

For syntax, kubectl label, selector grammar, and troubleshooting, continue to the Kubernetes labels and selectors guide in Related guides.


When to use annotations

Use annotations when the value describes the object and should not drive selection:

  • Release traceability when selectors do not need the value — or use a label such as app.kubernetes.io/version when users or tools must filter by revision
  • Owner, on-call, or team contact strings
  • Links to runbooks, diagrams, or external docs
  • Tool-specific configuration read by one controller (check that controller’s docs)
  • Structured JSON for operators or GitOps — as a single string value

For kubectl annotate, overwrite/remove syntax, and the 256 KiB limit, continue to the Kubernetes annotations guide in Related guides.


Selectors ignore annotations

kubectl get -l, Services, Deployments, and NetworkPolicies evaluate metadata.labels; they never search metadata.annotations. Annotations are ignored by label selectors, but annotations used by Ingress controllers, operators, or other extensions can alter object behavior when those tools watch documented keys.


Decision checklist

Question If yes → If no →
Must users or tools select/filter by this value? Label, provided it satisfies label syntax Annotation
Is it only release traceability or descriptive context? Annotation Label if selectors need it
Must kubectl get -l or a Service find objects by this value? Label Annotation
Must a Deployment selector match Pods by this key? Label on the Pod template Annotation
Is the value a URL, long string, or JSON blob? Annotation Label (if short enough)
Is it only for humans or an optional tool? Annotation Label if selectors need it

What's Next


References


Summary

Labels in metadata.labels identify and group objects; selectors and kubectl get -l match them. Annotations in metadata.annotations store descriptive metadata selectors ignore. Use labels for app identity, environment, tier, and anything Services or controllers must match — including a version or build ID when you need to select by it. Use annotations for traceability-only release metadata, URLs, owner contacts, and tool-specific data that should not drive selection.


Frequently Asked Questions

1. Can kubectl get -l filter by annotations?

No. kubectl -l and Service, Deployment, and NetworkPolicy label selectors match metadata.labels only. To work with annotations, use kubectl annotate and kubectl get -o yaml or jsonpath. See Kubernetes annotations.

2. Should I put a Git commit or build ID in a label or an annotation?

Use a label when you need to filter, select, or group by that value and it satisfies label syntax — for example app.kubernetes.io/version. Use an annotation when the value is traceability-only and must not participate in selection. The deciding factor is whether the value must be selectable, not whether it changes every release.

3. Can the same key exist as both a label and an annotation?

Yes. metadata.labels and metadata.annotations are separate maps on the same object. Avoid duplicating the same semantic data in both unless a tool explicitly requires it — pick one purpose per key.

4. Where do I learn kubectl label and kubectl annotate in depth?

Use Kubernetes labels and selectors for labels, selectors, and matchLabels. Use Kubernetes annotations for annotation syntax, kubectl annotate, and troubleshooting.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)