skip to content

In Kubernetes ObjectMeta, what do the server-populated uid, generation and resourceVersion fields each tell you, and what does generateName do?

level: middleimportance: should knowfreq 42%

answer

  1. identity, desired state, any write
  2. delete and recreate changes one
  3. compare with observedGeneration
  4. opaque, equality only
  5. five random characters, create not apply

basics

~20 s

uid identifies one incarnation of an object, so delete-and-recreate yields a new one. generation counts desired-state changes, resourceVersion changes on every stored write, and generateName makes the server append a random suffix to a name prefix.

solid answer

~50 s

`metadata.uid` is assigned at creation, never changes, and is unique in time and space — recreate an object under the same name and it gets a new `uid`, which is why references such as `ownerReferences` carry it. `metadata.generation` is a sequence number for **desired state**: the API server bumps it when the spec changes (a Deployment also bumps it on annotation changes, because they are copied to its ReplicaSet), not on status writes, and controllers echo the value they acted on in `status.observedGeneration`. `metadata.resourceVersion` is an **opaque** string that changes on every write that alters the stored object, status and labels included; clients pass it back for optimistic concurrency and compare it only for equality. `metadata.generateName` is used when `name` is empty: the server appends five random characters to the prefix. Since Kubernetes 1.32 it retries a collision with a fresh suffix. `kubectl apply` refuses it, so use `kubectl create`.

code

bash · 1 line
bash
kubectl get deployment game-session -o jsonpath='{.metadata.uid}{"\n"}{.metadata.generation} {.status.observedGeneration}{"\n"}{.metadata.resourceVersion}{"\n"}'

go deeper

for a junior

Recall that uid never changes for an object's life, and that generateName makes the server finish the name with a random suffix.

for a middle

Explain which writes move generation versus resourceVersion, and how status.observedGeneration tells you whether a controller has caught up with the latest spec.

for a senior

Show where these fields break automation: name-keyed caches confusing recreated objects, readiness checks that ignore observedGeneration, and non-idempotent generateName creates in retried pipelines.

for a principal

Argue for platform conventions: controllers that always publish observedGeneration, tooling that keys on uid rather than name, and a rule on when server-generated names are acceptable.

## Fields you write and fields the server writes Every persisted Kubernetes object carries **ObjectMeta**. Some of its fields are yours (`name`, `namespace`, `labels`, `annotations`), and some are **populated by the system and read-only** for clients. Three of the server-written ones answer different questions, and mixing them up leads to broken automation: | Field | Question it answers | Changes when | |---|---|---| | `uid` | Is this the same object I saw before? | Never, for the life of the object | | `generation` | Has the desired state changed? | On spec changes (kind-specific rules) | | `resourceVersion` | Has anything in the stored object changed? | On every write that alters it | A fourth field, `generateName`, is one you write, but it asks the server to pick the name for you. ## uid: identity of one incarnation `metadata.uid` is generated when the object is created and cannot change on update. The API documentation calls it unique in time and space. The key consequence: - Delete the `game-session` Deployment and create it again from the same YAML, and the **name is the same but the `uid` is different**. - References that must not confuse two incarnations carry the `uid`: `ownerReferences` include it, and Events record the `uid` of the object they describe. - A controller that caches work by name alone can wrongly apply stale state to a recreated object; caching by `uid` avoids that. ## generation and observedGeneration `metadata.generation` is a **sequence number of the desired state**. It starts at 1 on create and the API server's per-kind update logic decides when to bump it: - **Deployment**: bumped when `spec` changes (including `spec.replicas` from `kubectl scale`) and also when `metadata.annotations` change, because the controller copies those annotations to the newest ReplicaSet. - **Pod**: bumped when the pod spec changes; since Kubernetes 1.35 Pods also report `status.observedGeneration`. - **Status writes** through the `/status` subresource do not bump it, and a ConfigMap never sets it at all. Controllers write the generation they last acted on into `status.observedGeneration`. The pair is how you know whether status is current: 1. You change the game-session Deployment's CPU request from `250m` to `350m`; `generation` goes from 6 to 7. 2. Until the Deployment controller processes it, `status.observedGeneration` still says 6, and every other status field describes the **old** spec. 3. Once it reads 7, `status.updatedReplicas` and the conditions refer to the new template. A readiness check that ignores this can declare the new version healthy while it is still looking at the previous one. ## resourceVersion: an opaque change marker `metadata.resourceVersion` changes on **every write that alters the stored object** — spec, status, labels, annotations, finalizers. Its rules: - Treat it as **opaque**: pass it back unmodified and compare only for equality. Do not parse it or order values with less-than. - Send it with an update to get **optimistic concurrency**: the API server rejects the update if the object changed since you read it. - It is not a desired-state counter; a status heartbeat moves it while `generation` stays put. Its role in list and watch requests belongs to watch mechanics and is not covered here. ## generateName: let the server choose When `metadata.name` is empty and `metadata.generateName` is set, the API server builds the name from the prefix plus **five random lowercase alphanumeric characters**, trimming the prefix to 58 characters so the result fits 63. It suits objects created many times from one template, such as a replay Job per finished match on the retail-store edge cluster (`match-replay-` becomes `match-replay-x7k2q`). - If the generated name already exists, the server retries with a fresh suffix — up to **8 attempts** in total — before returning a conflict. This retry has been GA since Kubernetes 1.32. - The returned object carries the real name; read it from the response, because the manifest does not contain it. - **Declarative tools cannot use it**: `kubectl apply` fails with `cannot use generate name with apply`, since apply must find the same object again by name. Use `kubectl create` instead. - Re-running a create with `generateName` makes a **new** object every time, so it is not idempotent.

  • Why does a Kubernetes Deployment's generation change when only its annotations are edited?
    The Deployment update logic in the API server bumps `generation` when the spec changes or when `metadata.annotations` change, because the Deployment controller copies annotations onto the newest ReplicaSet. Bumping the generation makes the controller treat the edit as work to process and lets `status.observedGeneration` show when that copy has happened. No new pods are created; only the template triggers a rollout.
  • Why should a deployment check compare `status.observedGeneration` with `metadata.generation` before trusting other status fields?
    Until the controller has observed the latest generation, every status field describes the previous spec. A check that reads ready or updated replica counts too early can report success for the old version. Waiting until `observedGeneration` equals `generation` guarantees the status belongs to the spec you just submitted; `kubectl rollout status` does this check.
  • What does the API server do when a name generated from `generateName` already exists?
    It generates a new random suffix and tries the create again, up to 8 attempts in total, and returns a conflict only if every attempt collides. This has been standard behaviour since Kubernetes 1.32; earlier releases returned the conflict on the first collision and left the retry to the client.

saying these in an interview costs you the question

  • resourceVersion is a number you can compare with less-than to order writes.
  • generation goes up whenever an object's status or labels change.
  • A recreated object with the same name keeps its old uid.
  • generateName works with kubectl apply for repeatable deployments.
  • generation and resourceVersion are two names for the same counter.