Skip to main content
A number can tell you the gauge reading. A condition tells you what the reading means. In Kubernetes controllers, numeric status fields (for example, ReadyReplicas) are gauges — they show measurements. Conditions are the dashboard lights beside those gauges. If a web app’s spec requests three replicas but only one is ready, ReadyReplicas gives the count. A condition answers the human questions that follow:
  • Is this still rolling out?
  • Is it healthy enough?
  • Or is something stuck?
Think of conditions as compact, machine- and human-friendly health signals. They belong in status because status is the controller’s report about the real cluster: spec is the user’s intent; status is what the controller actually observes. Kubernetes provides a shared shape for these reports via metav1.Condition.
The image is a flowchart illustrating the process of a controller observing what is asked and determining the conditions, with the headline "Conditions Belong in Status."
What is a condition? At its simplest, a condition is one dashboard light with:
  • Type — a name for the light
  • Status — the current state (True, False, Unknown)
  • Reason — a short, stable, machine-friendly label
  • Message — a human-readable sentence explaining the observation
  • LastTransitionTime — when the condition last changed
  • ObservedGeneration — which metadata.generation the status reflects
A real-world example in Go:
Fields mapped to intent and usage: Do not confuse LastTransitionTime with frequent reconciles: it should only change when the condition flips. That allows operators to know how long a resource has been in a particular state. ObservedGeneration prevents stale green lights: if Ready is True but ObservedGeneration is older than the latest metadata.generation, the status refers to a previous spec. Example YAML snippet that separates machine- and human-facing fields:
Core condition types to keep in most controllers
  • Ready — Does the resource meet the requested state (e.g., deployment has required ready replicas)?
  • Progressing — Is the controller still moving toward that state (e.g., during a rollout)?
  • Degraded — Has the controller observed a problem that blocks normal operation?
These three lights provide a focused view without turning status into a crowded control panel.
The image explains three condition types using traffic lights: "Ready" (green), "Progressing" (yellow), and "Degraded" (red), each associated with a question about system status. A note suggests asking steady questions instead of keeping a diary.
Keep condition types steady and focused: they should ask continuous health questions (Ready, Progressing, Degraded), not log every event or reconcile step.
Design guidance and best practices
  • Keep condition types stable and few. They are part of your API’s contract and are used by alerts, dashboards, and other controllers.
  • Make Reason predictable and machine-friendly; use Message for human context.
  • Only update LastTransitionTime when the condition value actually changes.
  • Populate ObservedGeneration so users can detect stale status.
A single resource can show multiple lights at once. Conditions are not a single giant state machine — they answer independent questions. For example, during a rollout:
  • Progressing can be True while Ready is False.
  • In steady state, Ready can be True while Degraded is False.
The image shows a diagram explaining two conditions: "Rollout" with progress lights indicating "Progressing" (True) and "Ready" (False), and "Steady state" with lights indicating "Ready" (True) and "Degraded" (False).
Do not overload conditions with transient or debug-level events. Conditions should answer steady-state health questions, not act as a message log.
Keep the dashboard small and pragmatic. For a typical web app controller, the three lights (Ready, Progressing, Degraded) give operators and tools the context they need without forcing them to interpret raw gauges alone. Next demo: we’ll start with the simplest gauge — ready replicas — and show how to map that measurement into the Ready condition. Good status design makes controllers and clusters easier to understand, debug, and operate. Links and further reading

Watch Video