kubectl label: Add and Remove Labels
kubectl label sets or removes labels on one or many resources; removing a label uses the key- suffix.
Labels drive selectors, rollouts, and policy. label edits them in place without touching the rest of the manifest.
What it does
kubectl label adds or updates key=value labels on the named resources. Adding a label that already exists requires --overwrite; appending a trailing - to a key removes it. A --selector lets you label every matching resource at once.
Common usage
kubectl label pod api-0 tier=web
# change an existing label (needs --overwrite)
kubectl label deploy api version=v2 --overwrite
# remove a label
kubectl label deploy api version-
# label all matching resources
kubectl label pods -l app=api canary=trueOptions
| Flag / Syntax | What it does |
|---|---|
| <key>=<value> | Set a label |
| <key>- | Remove the label with that key |
| --overwrite | Allow changing an existing label value |
| -l, --selector | Apply to all resources matching a selector |
| --all | Apply to all resources of the type |
| --dry-run=client | Preview without writing |
In CI
Always pass --overwrite when a label may already be set, otherwise repeated runs fail. Editing the labels inside spec.selector of a Deployment or Service is not allowed (selectors are largely immutable); change pod template labels with care since they trigger a rollout.
Common errors in CI
"error: \'version\' already has a value (v1), and --overwrite is false" means add --overwrite. "the Deployment ... is invalid: spec.selector: Invalid value: ... field is immutable" means you tried to relabel an immutable selector; recreate the object. "error: at least one label update is required" means you passed no key=value or key- argument.
Using this in CI
A runner has no kubeconfig, no cached context, and no interactive auth. Every kubectl invocation in CI needs the context supplied explicitly, and most confusing CI failures here are the command running against the wrong cluster or no cluster at all.
# never rely on the ambient context on a runner
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" get pods
# confirm what you are actually connected to before mutating anything
kubectl config current-context
kubectl cluster-info
# fail fast instead of hanging on an unreachable API server
kubectl --request-timeout=30s get nodes