Kubernetes Object Structure
Kubernetes Object Structure defines the building blocks of Kubernetes, detailing how resources are organized and managed within a cluster environment.
Kubernetes Object Structure is the concrete field-level shape every persistent Kubernetes API object shares, defining the standard building blocks — type identification, metadata, desired state, and observed state — that every object, whether a built-in Pod or a third-party custom resource, is assembled from. Understanding this structure is what makes it possible to read an unfamiliar resource type's manifest and immediately recognize its identity, ownership, and intent, even before understanding the specifics of what that particular Kind does.
TypeMeta
apiVersion and kind
Every object begins with apiVersion and kind, together forming the GroupVersionKind that identifies exactly what schema the rest of the document should be interpreted against; these two fields are what the API server's decoder reads first to determine how to parse and validate everything that follows, before any other field is even considered.
Why TypeMeta Is Not Nested
Unlike most structured fields in an object, apiVersion and kind appear directly at the top level rather than nested under a typeMeta key, a deliberate serialization choice that keeps type identification immediately visible at the start of any manifest, JSON payload, or API response.
ObjectMeta
Identity Fields
metadata.name (and metadata.namespace, for namespaced resources) together provide an object's addressable identity, while metadata.uid provides a globally unique identifier assigned by the API server at creation time that remains stable even if the object is deleted and a new object with the same name is later created.
Labels and Annotations
metadata.labels holds key-value pairs intended for identifying and selecting subsets of objects, consumed by selectors in Services, ReplicaSets, and NetworkPolicies among others, while metadata.annotations holds arbitrary key-value metadata not intended for selection, commonly used to attach tooling-specific configuration or human-readable notes that have no bearing on object matching logic.
Owner References and Finalizers
metadata.ownerReferences establishes parent-child relationships between objects, which the garbage collector uses to cascade-delete dependents when an owner is deleted, while metadata.finalizers lists identifiers that must be cleared by their respective controllers before the API server will complete the object's actual deletion, allowing controllers to perform cleanup work that must happen before an object truly disappears.
resourceVersion and generation
metadata.resourceVersion changes on every write to the object and underpins optimistic concurrency control, while metadata.generation, present on types that support it, increments only when the object's spec changes, giving controllers a way to distinguish a meaningful desired-state change from a status-only update.
Spec
Desired State Declaration
The spec field, whose internal schema is entirely specific to the object's Kind, holds the desired state a client is declaring — for a Deployment, this includes the desired replica count and Pod template; for a Service, the selector and port mappings — and it is this field, and essentially only this field, that ordinary users and GitOps pipelines are expected to author and modify directly.
Immutability of Certain Spec Fields
Some fields within spec are mutable throughout an object's life while others become immutable once set, such as a Pod's node assignment once scheduled; this partial immutability is enforced by the API server's validation logic on updates and reflects which desired-state changes can be reconciled in place versus which require the object to be replaced entirely.
Status
Observed State Reporting
The status field, when present, holds the last observed actual state as reported by whichever controller is responsible for that Kind, and by convention should be fully derivable from the current state of the world such that it could, in principle, be recomputed from scratch by the controller without any loss of information.
Status as a Protected Subresource
For most built-in types, status is writable only through the dedicated status subresource, which is enforced through RBAC separately from the main resource path, structurally reinforcing the convention that ordinary clients declare spec while controllers report status, rather than both flowing through the same unguarded write path.