Skip to main content
In this lesson you’ll learn how kubectl apply works internally and why it needs three sources of truth to determine what changes to make. Understanding this three-way merge model helps you avoid accidental overwrites and ensures predictable, declarative management of Kubernetes resources. Quick examples (declarative applies)
Example manifest (local file nginx.yaml)
Overview — the three configurations
  • Local configuration: the manifest file on your workstation (for example nginx.yaml).
  • Live configuration: the object currently stored in the Kubernetes API (includes status and other cluster-managed fields).
  • Last-applied configuration: a JSON snapshot of your last kubectl apply run, stored on the live object as the annotation kubectl.kubernetes.io/last-applied-configuration.
Table: three sources used by kubectl apply What happens when you run kubectl apply
  1. Create: If the object does not exist, kubectl apply creates it. When created:
    • The cluster stores the live configuration.
    • kubectl writes the local manifest (converted to JSON) into the kubectl.kubernetes.io/last-applied-configuration annotation on that live object.
  2. Update: For subsequent runs, kubectl performs a three-way comparison between:
    • the local manifest,
    • the last-applied configuration (from the annotation),
    • and the live configuration. Based on that comparison it computes a patch (typically a strategic merge patch for supported resources) and applies only the necessary changes to the live object. After applying, kubectl updates the last-applied annotation with the JSON representation of the new manifest.
Example: updating the image Suppose you update your local manifest to nginx:1.19 and then run kubectl apply -f nginx.yaml. Local manifest (updated)
Live configuration before update (simplified — includes status)
Run:
What kubectl does:
  • Compares local manifest vs last-applied vs live.
  • Detects the image change from nginx:1.18 to nginx:1.19.
  • Computes and applies a minimal patch to update only the image field.
  • Updates the kubectl.kubernetes.io/last-applied-configuration annotation with the JSON of your new manifest.
Why the last-applied configuration is necessary The last-applied snapshot allows kubectl to determine whether a field in the live object was introduced by kubectl apply (and should be managed by subsequent applies) or was added directly on the cluster by some other actor. Concretely:
  • If a field is present in the last-applied configuration but missing from your current local manifest, kubectl apply treats that as an intentional removal and will remove it from the live object.
  • If a field is present in the live object but not present in either the current local manifest or the last-applied configuration, kubectl apply assumes that field was added by another actor and generally leaves it unchanged.
Example: removing a label locally Local manifest (label type removed)
Last-applied annotation (stored JSON — simplified)
If the live object still contains type: front-end-service, running kubectl apply -f nginx.yaml will remove that label because it existed in the last-applied snapshot but is missing from your current local manifest. Where the last-applied JSON is stored The last-applied configuration is saved on the live object itself under the annotation: kubectl.kubernetes.io/last-applied-configuration Note that this behavior is specific to kubectl apply. Commands like kubectl create or kubectl replace do not set this annotation unless you replicate the behavior manually. A few practical notes
Do not mix imperative and declarative operations on the same fields: if you use kubectl apply to manage a field, avoid making ad-hoc kubectl edit or kubectl patch changes to that same field unless you understand how that will interact with the last-applied snapshot. Mixing approaches can lead to unexpected removals or overrides.
  • Historically, kubectl apply implements a client-side three-way merge using the last-applied annotation. Server-side apply (SSA) is a newer approach that uses managedFields and different semantics; choose the model that fits your workflow and tooling.
  • If you rely on automated controllers or operators that modify resource fields, consider using server-side apply or coordinating ownership to avoid friction with declarative kubectl apply.
  • For edge cases and full semantics, see the Kubernetes documentation:
That covers the internal workflow of kubectl apply, the role of the last-applied configuration, and practical guidance to avoid common pitfalls.

Watch Video