What is a Kubernetes object, and what do apiVersion, kind, metadata, and spec mean?
Quick Answer
A Kubernetes object is a persistent record in the cluster (stored in etcd) representing the desired state of something — a Pod, a Deployment, a Service. Every object's manifest has four key top-level fields: `apiVersion` (which version of the API this object's schema belongs to), `kind` (what type of object it is), `metadata` (identifying information — name, namespace, labels, annotations), and `spec` (the desired state you're declaring). Most objects also get a `status` field, populated by the system, reflecting the observed actual state.
Detailed Answer
Anatomy of a manifest
apiVersion: apps/v1 # which API group/version defines this object's schema
kind: Deployment # what type of object this is
metadata:
name: web # this object's unique name (within its namespace)
namespace: production
labels:
app: web
tier: frontend
spec: # DESIRED state -- what you're declaring you want
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: myapp:1.4.0
status: # ACTUAL observed state -- populated BY Kubernetes, not by you
availableReplicas: 3
updatedReplicas: 3
apiVersion
Identifies which version of which API group defines this object's schema — core objects like Pods and Services use v1; most workload objects (Deployments, StatefulSets, DaemonSets) use apps/v1; networking objects use networking.k8s.io/v1, and so on. This matters because Kubernetes APIs evolve — a field available in v1 might not exist in an older v1beta1 version of the same kind, and using the wrong apiVersion for your cluster's Kubernetes version is a common source of "field not recognized" errors.
kind
The type of object being described — Pod, Deployment, Service, ConfigMap, and so on. Combined with apiVersion, this tells the API server exactly which schema to validate the rest of the manifest against.
metadata
Identifying and organizational information about the object itself, not its desired behavior: name (unique within its namespace), namespace (which logical partition of the cluster it belongs to), labels (key-value pairs used for selection/grouping — Services and Deployments use label selectors to find the Pods they manage), and annotations (non-identifying metadata, often used by tooling rather than Kubernetes itself — e.g., a value read by an Ingress controller or a CI/CD tool).
spec
The heart of the object — what you're declaring you want to be true. For a Deployment, this includes the desired replica count and the Pod template to use; for a Service, the ports and selector; for a PersistentVolumeClaim, the requested storage size and access mode. This is the "desired state" half of the reconciliation model (see that question) — you write the spec, and a controller works to make reality match it.
status
Populated by Kubernetes itself (never written directly by a user in a normal workflow) to reflect the object's currently observed actual state — how many replicas are actually available, what phase a Pod is in, and so on. Comparing spec (desired) against status (actual) is exactly what a reconciliation control loop does on every iteration.
Why this consistent structure matters
Every object type in Kubernetes — built-in or a Custom Resource you define yourself (see that topic) — follows this same apiVersion/kind/metadata/spec/status shape, which is precisely what lets generic tooling (kubectl, Helm, GitOps controllers) work uniformly across every object type without needing type-specific logic for each one.