Kubernetes Server-Side Apply: Field Ownership, Conflicts, and managedFields
How Server-Side Apply records field ownership, detects conflicting intent, supports shared objects, and differs from replacement and merge patch workflows.
Kubernetes objects are frequently edited by several actors: a GitOps controller owns the Deployment template, an autoscaler changes replica count, a mutating admission controller adds defaults, and an operator may perform an emergency edit. Server-Side Apply (SSA) gives the API server a vocabulary for those simultaneous intentions by recording which manager owns which fields and rejecting incompatible changes instead of silently overwriting them.
Apply is an intent operation, not a complete replacement
An SSA request uses the apply patch media type and supplies a field manager name. The submitted object expresses the fields that manager intends to own. Fields previously owned by that manager but omitted from its new configuration may be cleared or fall back to another manager/default, while unrelated fields owned by others remain.
kubectl apply --server-side \
--field-manager=platform-gitops \
-f deployment.yaml
That differs from PUT, which replaces an object representation subject to API semantics, and from JSON Merge Patch or Strategic Merge Patch, which describe mutations but do not establish the same durable ownership model. Client-side apply historically stored a last-applied annotation and calculated a patch locally; SSA performs the merge and conflict detection using the schema and ownership data on the server.
managedFields is the ownership ledger
Object metadata can include managedFields entries containing a manager, operation, API version, timestamp, and a compact field set. The data is verbose because it is machine state, not an editorial changelog.
kubectl get deployment api \
-o yaml --show-managed-fields
Ownership is field-granular and schema-aware. In structured list types, Kubernetes can treat entries as a map keyed by declared fields rather than one indivisible array. The CustomResourceDefinition schema therefore matters: inaccurate or absent structural markers can make ownership coarser than an API designer expects.
The manager string should identify a stable actor and purpose, such as delivery-controller, not a random build ID. Generating a new manager for every run accumulates ownership entries and makes conflicts difficult to interpret.
Conflicts are evidence of competing intent
If manager A owns a field and manager B applies a different value, the API returns a conflict. The correct response is to determine which actor should own the field, not automatically add --force-conflicts.
kubectl apply --server-side \
--field-manager=platform-gitops \
--force-conflicts \
-f deployment.yaml
Forcing the apply transfers ownership of conflicting fields and writes the new values. It is appropriate only after an explicit ownership decision. A continuously reconciling pair of managers that force the same field back and forth creates a control loop, audit noise, and possibly workload disruption.
Shared ownership can be deliberate
Two managers can co-own a field when they apply the same value. If one later changes it, the other manager’s unchanged intent can produce a conflict. Shared ownership is useful for jointly asserted invariants but should not be an accidental side effect.
The replicas field illustrates why ownership design matters. If a deployment manager applies .spec.replicas while an HPA also changes it, subsequent applies can reset autoscaling decisions. Omitting replicas from the delivery manager’s intent lets the autoscaler own it. Similar boundaries apply to image automation, policy labels, and admission-injected fields.
Schema evolution changes merge behavior
SSA relies on OpenAPI schemas and structural CRD definitions. Changing a field from atomic to granular, or correcting list-map keys, can alter how ownership is tracked. Kubernetes warns that removing fields from a schema can leave managers with ownership of data the new schema no longer exposes normally. Test CRD upgrades with multiple field managers and existing objects, not only clean creates.
Defaulting also participates in the final object. A manager should apply the API version it understands and avoid claiming defaults merely by round-tripping a fully materialized object copied from kubectl get. Keep desired manifests intentional rather than treating the server’s complete output as an apply input.
Audit ownership as part of controller design
For each controller, document its field manager, resource kinds, owned paths, conflict policy, and migration process. Test create, repeat apply, field removal, takeover, co-ownership, defaulting, conversion webhooks, and rollback. Alert on unexpected conflict rates; a conflict can reveal a newly overlapping controller before it becomes a silent overwrite.
SSA does not decide organizational ownership. It makes ownership machine-visible and refuses ambiguous changes, giving operators a safer point at which to make that decision.
Related:
- Kubernetes QoS Classes: How Requests and Limits Shape Eviction and Scheduling
- How to Order Argo CD Deployments with Sync Phases, Waves, and Hooks
Sources: