Desired State
Desired state is the configuration you declared, held separately from the state that actually exists. You write what you want; the system records what it has; something else works to close the distance. The pattern is most visible in Kubernetes, whose documentation calls an object “a record of intent” — “once you create the object, the Kubernetes system will constantly work to ensure that the object exists.” Quotations here are from that documentation as read in September 2026; field names are versioned.
Two fields, two authors
The separation is literal. Almost every Kubernetes object carries a spec and a status.
spec— “a description of the characteristics you want the resource to have: its desired state.” You set this.status— “the current state of the object, supplied and updated by the Kubernetes system and its components.” The system sets this.
And the promise attached to the pair: “the Kubernetes control plane continually and actively manages every object’s actual state to match the desired state you supplied.”
Follow one replica failing to see what that means in practice. Declare three replicas, and “if any of those instances should fail (a status change), the Kubernetes system responds to the difference between spec and status by making a correction — in this case, starting a replacement instance.” Nobody was notified and nobody acted. The difference itself was the trigger.
A declaration is not a command
This is where the model breaks most people’s habits, because both styles are expressed by running something at a terminal and both can print a success message.
| Imperative command | Declared desired state | |
|---|---|---|
| What it means | Do this now | This is what I want to be true |
| Completion | Returns when done or failed | No completion event — the goal has no end |
| Failure | An error you receive | A gap that persists, reported where you have to look |
| Running it twice | May do the work twice | Second one changes nothing — the state is already declared |
| Drift afterwards | Nobody notices | Corrected, because the declaration is still in force |
The fourth row is why declarative interfaces are pleasant to automate: re-applying is safe by construction, which is idempotency obtained from the shape of the interface rather than from careful coding. The second and third rows are the cost, and they are what the next section is about.
A request, not a guarantee
Declaring something does not make it possible. If you ask for a workload no machine in the fleet can host, the platform does not reject it — in Kubernetes, “if none of the nodes are suitable, the pod remains unscheduled until the scheduler is able to place it.” There is no timeout in that sentence. The object is valid, the intent is recorded, and the intent is simply unmet, indefinitely.
Even the mechanism that does report a stall reports it as a field rather than an outcome. A Deployment that cannot progress gets a condition written into its status — “type: Progressing, status: 'False', reason: ProgressDeadlineExceeded” — after a deadline that “defaults to 600” seconds. And the crucial sentence: “the Deployment controller will keep retrying the Deployment.“
So “failed” here means reported as not progressing, not stopped. Nothing gave up, nothing reverted. If you want failure to halt and roll back, that is behaviour you build on top by reading the condition and acting — see rollback for what reverting actually requires.
What you monitor instead of completion
Since there is no completion event, watching for one produces dashboards that are confidently wrong. Two quantities replace it.
- The gap between what is declared and what exists.
- How long the gap has been open. This is the one that carries the signal. A gap right after a change is the system working; the same gap twenty minutes later is an incident. Only the duration distinguishes them, and the threshold is yours to set — it is a statement about how stale you are willing for reality to be, which makes it an SLO-shaped decision rather than a platform default.
A related point that reads as alarming and is not: the documentation notes that “your cluster could be changing at any point as work happens and control loops automatically fix failures. This means that, potentially, your cluster never reaches a stable state.” Convergence is not the success criterion. Continuous movement toward the declaration is. See control loop for the mechanism that does the moving.
Continuous enforcement or point-in-time comparison
Declarative infrastructure tooling shares the vocabulary and behaves differently, and the difference is worth naming because people transfer expectations between them. A tool driven by a state file compares your declaration to its record when you run it; between runs nothing is checking, which is how configuration drift accumulates and has to be detected. See infrastructure as code and the infrastructure state file.
A continuously reconciling platform does not wait to be run, so drift in what it manages is corrected without anyone asking. The trade is symmetrical: you get repair you did not request, and you lose the moment when someone would have noticed. A manual fix applied directly to a managed object gets quietly undone, which is correct behaviour and surprising the first time.
The pattern is not specific to containers. Any system where you record intent and a background process works toward it has the same properties — no completion, failure as a persistent condition, safe repetition, and correction you did not ask for. Recognizing it is what stops you from looking for a return value that the design never had.
References, read September 2026: Kubernetes: Objects In Kubernetes; Controllers; Deployments; Kubernetes Scheduler. Field names and defaults are versioned.
Discover more from Insightful Data Lab
Subscribe to get the latest posts sent to your email.
