Server-Side Apply | Kubernetes
Kubectl Create vs Kubectl Apply
Core Idea
Client-side apply lets
kubectlmerge diffs locally and can fight other writers; server-side apply hands conflicts to the API server through field ownership, so it is explicit who owns which field.
- CSA: kubectl computes the diff and patches from the client, which breaks down when multiple managers edit the same object.
- SSA: each writer is a field manager, the server detects conflicts, and collaborative edits become possible.
- The note keeps a quick comparison table plus a deep dive on server-side apply behavior.
Transclude of 3.-interacting-with-kubernetes#managing-objects
Client-Side Apply (CSA)
This is the original, default behavior of kubectl apply.
How it works:
- All the “diffing” logic happens on your local machine (in
kubectl). kubectlstores the last applied configuration as a JSON blob in an annotation on the object:kubectl.kubernetes.io/last-applied-configuration.- On each
apply, it computes a three-way merge using:- The last-applied-configuration annotation (what you applied last time)
- The current live object on the cluster
- The new configuration you’re applying now
- Based on this diff, it figures out which fields to add, update, or remove.
Limitations
- The annotation has a size limit (~256KB), which can be an issue for large objects.
- Field ownership tracking is fragile — it doesn’t know which controller or user owns which field, only what was in your last local apply.
- Merge conflicts between multiple tools/users managing the same object aren’t well handled — you can accidentally overwrite fields another tool manages.
- Merge logic is client-side, so behavior can vary depending on the
kubectlversion.
Server-Side Apply (SSA)
Introduced as beta in Kubernetes 1.16 and GA (stable) since 1.22, SSA moves the merging logic into the API server itself.
How it works:
- Instead of a last-applied-configuration annotation, the API server tracks field ownership using
managedFieldsmetadata on the object. - Each field is associated with a “field manager” (e.g.,
kubectl, a controller, or a CI/CD tool) that last set it. - When you apply, the API server merges your intent with the live object, based on who owns which field — it can detect and report conflicts if two managers try to own the same field.
- You use it via
kubectl apply --server-side(or set it as default in newer kubectl behavior for certain workflows).
Advantages
- No annotation size limits — no giant JSON blob stored on the object.
- Proper multi-actor field ownership — multiple controllers/users can co-manage different parts of the same object safely.
- Conflict detection: if another manager owns a field you’re trying to change, the API server will reject the apply unless you pass
--force-conflicts. - More consistent behavior since logic lives in the API server, not scattered across
kubectlclient versions.
Quick Comparison
| Aspect | Client-Side Apply | Server-Side Apply |
|---|---|---|
| Where merge happens | kubectl (client) | API server |
| Ownership tracking | last-applied-configuration annotation | managedFields metadata |
| Size limits | Yes (~256KB annotation) | No |
| Multi-owner conflict detection | Poor/none | Built-in |
| Command | kubectl apply -f file.yaml | kubectl apply --server-side -f file.yaml |
| Status | Legacy default | Recommended going forward |
Tip
If you’re mixing tools (e.g.,
kubectl, Helm, a custom operator, GitOps tools like ArgoCD/Flux) managing the same resources, Server-Side Apply is strongly recommended because it handles shared ownership and conflicts far more gracefully. Many GitOps tools have already switched to SSA by default for this reason.
Server Side Apply Deep Dive
Introduction
A Kubernetes object is shared state.
A Deployment is not managed solely by the YAML file that created it; it can also be touched by kubectl, Helm, Argo CD, an HPA, admission webhooks, operators, and built-in controllers.
All of them can write to the same API object.
That raises a simple question: when several tools care about the same field, who owns it?In a small cluster, this can look like an implementation detail.
In a real cluster, it decides whether an HPA keeps the replica count it just calculated, whether a Helm upgrade undoes a manual hotfix, or whether a GitOps controller reverts a change made by another controller.
Link to original
This article explains whyapplyhas to do more than “send this YAML to Kubernetes”.
It has to decide what changed, what should be preserved, and what another tool might already be managing.
To understand why this is hard, let’s start with whatkubectl applydoes today.