Almost every task on the CNCF Kubernetes exams ends the same way: you have a manifest, and you need to make the cluster match it. But there are three different ways to do that with kubectl, they behave differently, and picking the wrong one is a quiet source of lost points — a create that fails because the object already exists, a replace that wipes a field a controller set, or an apply that behaves unexpectedly because someone ran create first.
This guide is the “which mode, and why” companion to raw syntax. If you want the fast command shapes to scaffold manifests, keep the CKA kubectl cheat sheet open in a second tab. Here we go one level deeper: the three object-management approaches Kubernetes actually supports, what apply does under the hood, and the exact command to reach for when a task says “the resource may already exist” or “change the immutable field.” These distinctions show up across the CKA, CKAD and CKS performance exams, and the concepts are tested directly on the KCNA — so if you are working the KubeAstronaut path, you meet them in every exam.
The Three Ways to Manage a Kubernetes Object
Kubernetes officially recognizes three techniques for managing objects. You should use exactly one technique per object over its lifetime — mixing them is where surprises come from.
| Technique | Commands | Operates on | Best for |
|---|---|---|---|
| Imperative commands | kubectl run, create deployment, expose, scale, set image, edit, delete | Live objects, no file | Speed on the exam; one-off changes |
| Imperative object config | kubectl create -f, replace -f, delete -f | Individual files | Version-controlled files, full control, exact operations |
| Declarative object config | kubectl apply -f, diff -f | Files and directories | Production, GitOps, many actors on one object |
The mental split: imperative means you state the operation (create this, replace that, scale to 3). Declarative means you state the desired end state in a file and let kubectl apply figure out the operation. The exam rewards imperative commands for raw speed, but the object you end up applying is almost always managed with apply.
Imperative Commands: Fast, but Stateless
Imperative commands act directly on live objects with no manifest in between:
# Create a Deployment in one line
kubectl create deployment web --image=nginx:1.27
# Change one thing about a live object
kubectl scale deployment web --replicas=4
kubectl set image deployment/web nginx=nginx:1.28
kubectl label pod web-xyz tier=frontend
These are unbeatable for speed, which is why they dominate exam workflows. The catch is that there is no source of truth on disk: the “configuration” lives only in your shell history. You cannot easily review a change, roll it back from a file, or reproduce it. That is fine for a 2-hour exam and wrong for a real platform.
The one imperative command that behaves like a hybrid is kubectl edit: it pulls the live object into your $EDITOR, and on save it submits your changes as an update. It is convenient for a quick fix, but just as unreproducible as the rest.
The exam pattern you actually use most is imperative-command scaffolding followed by a declarative apply — generate a manifest, edit it, then apply it:
kubectl create deployment web --image=nginx:1.27 \
--dry-run=client -o yaml > web.yaml
# edit web.yaml, then:
kubectl apply -f web.yaml
That single move — imperative speed to produce YAML, declarative apply to manage it — is the backbone of efficient exam work. It is the same discipline behind generating rolling-update Deployments and Jobs and CronJobs quickly.
apply vs create: The Difference That Bites
This is the single most common confusion, so make it mechanical.
kubectl create -f web.yaml fails if the object already exists — you get an AlreadyExists error. It is a one-shot “make this new thing” operation. Re-running it is an error, not a no-op.
kubectl apply -f web.yaml is idempotent: it creates the object if it is absent and updates it if it is present, and it records what you sent so it can merge intelligently next time. Run it ten times in a row and the result is the same.
kubectl create -f web.yaml # ok the first time
kubectl create -f web.yaml # Error: deployments.apps "web" already exists
kubectl apply -f web.yaml # ok
kubectl apply -f web.yaml # still ok — no error, computes the diff
So when an exam task hints that “the resource may already exist,” or asks you to reconcile a directory of manifests, reach for apply. When you want to guarantee a fresh object and want the failure if it is already there, create is the honest choice.
How apply Actually Works: The Three-Way Merge
kubectl apply (the classic, client-side form) is smart because it does a three-way merge. It compares three things:
- Your configuration file — what you want now.
- The
last-applied-configurationannotation — a copy of the last file you applied, stored by kubectl on the object underkubectl.kubernetes.io/last-applied-configuration. - The live object on the server — the current state, including fields other actors set.
From these three, apply computes a patch:
- A field you removed from your file (but that was in last-applied) gets deleted from the live object.
- A field you never managed — for example,
spec.replicasthat a HorizontalPodAutoscaler bumped to 6 — is preserved, because it is not in your file and not in last-applied. - A field you changed is updated.
This is why declarative apply is the right tool when multiple actors touch one object: it merges your intent with concurrent reality instead of stomping on it. You can inspect the stored annotation directly:
kubectl get deployment web -o jsonpath='{.metadata.annotations.kubectl\.kubernetes\.io/last-applied-configuration}'
Reading and filtering that output cleanly is a skill of its own — see the kubectl output formatting guide for the JSONPath escaping used above.
replace: Full Overwrite (and —force Recreates)
kubectl replace -f web.yaml is the imperative-object-config sibling of create. It does a full replacement of the object with the contents of your file — no merge. Anything present on the live object but absent from your file is dropped. That includes fields other controllers set, which is exactly why replace is dangerous for shared objects and why apply exists.
replace also requires the object to already exist (the opposite of create), and for some flows it wants the current resourceVersion, so people typically get -o yaml, edit, then replace.
The version you will actually reach for on the exam is --force:
kubectl replace --force -f pod.yaml
replace --force deletes the object and recreates it. This is the go-to move when a task requires changing an immutable field — something the API will refuse to update in place, such as a bare Pod’s spec, a Job’s selector, or a Service’s clusterIP. Because it recreates the object, expect a new UID and, for Pods, a restart. Never use it casually on a live production object; on the exam it is precisely the right tool when an in-place edit returns a “field is immutable” error.
A quick decision path when you need to change something:
- Object does not exist yet? Use
create -f(fail if present) orapply -f(create-or-update). - Changing an immutable field? Use
replace --force -f— it deletes and recreates the object. - Object is also touched by controllers or other actors? Use
apply -f— its three-way merge preserves the fields you do not manage. - A quick one-off change to an object you fully own?
apply -foreditboth work.
Server-Side Apply: Field Managers and Conflicts
Classic apply runs the merge logic on the client (in kubectl) and depends on that last-applied-configuration annotation. Server-Side Apply (SSA) moves the logic to the API server:
kubectl apply --server-side -f web.yaml
Instead of a client annotation, the server records field management in metadata.managedFields: every field is owned by a named field manager (your kubectl, a controller, an operator). When two managers try to own the same field, you get a conflict, and you either hand off ownership or force it:
kubectl apply --server-side --force-conflicts -f web.yaml
SSA has been the default merge engine for controllers for a while and is generally available for everyday use. You are unlikely to type --server-side under exam time pressure, but the KCNA and CKS reward understanding it: it is how controllers and multiple automation systems safely co-own one object without clobbering each other, and managedFields is where you look to see who set what. For the broader declarative and reconciliation picture, the Kubernetes object model guide covers the desired-state API that all of this sits on top of.
diff: Look Before You Apply
Before you change a cluster you do not fully trust, preview the change:
kubectl diff -f web.yaml
kubectl diff performs a server-side dry run of the merge and prints exactly what apply would change — added, removed, and modified fields — without touching anything. On the exam it is a fast sanity check; in production it is the difference between a clean change and an incident. Pair it with a client-side dry run when you only want to validate that your YAML is well-formed:
kubectl apply -f web.yaml --dry-run=client # local validation only
kubectl apply -f web.yaml --dry-run=server # validate against the API server + admission
The “Don’t Mix Modes” Trap
Here is the failure mode that catches people. You kubectl create -f web.yaml. There is now no last-applied-configuration annotation, because create does not write one. Later you kubectl apply -f web.yaml. Apply has no record of what it “last applied,” so its three-way merge degenerates — it can prune or misjudge fields in ways you did not expect, and older clients would even warn you.
The rule is simple: manage each object with one technique for its whole life. If it is a declarative object, apply it from the very first time. If you scaffolded it with an imperative command plus --dry-run=client -o yaml, apply the resulting file — do not create it and then switch to apply. Consistency here removes an entire class of “why did that field disappear?” mysteries.
Decision Table: Which Command When
| Situation | Reach for | Why |
|---|---|---|
| Scaffold a manifest fast | imperative create ... --dry-run=client -o yaml | Speed, then edit |
| Make a brand-new object, fail if it exists | create -f | One-shot, non-idempotent by design |
| Create-or-update, run repeatedly | apply -f | Idempotent three-way merge |
| Object is edited by controllers/HPA too | apply -f | Preserves fields you do not manage |
| Change an immutable field | replace --force -f | Deletes and recreates the object |
| Quick one-off fix to a live object | edit or scale/set | Fastest path, not reproducible |
| Preview a change safely | diff -f | Server-side dry-run of the merge |
| Many automation systems co-own one object | apply --server-side | Field managers + explicit conflicts |
Exam-Day Speed Tips
- Default to
apply, notcreate, for anything you built from a file. It never errors on re-run, which matters when you re-attempt a question. - When an in-place change returns “field is immutable,” stop editing and
replace --force. Do not fight the API — recreate. - Use
create --dry-run=client -o yamlto generate, thenapply. This is the fastest correct workflow and the one the CKA kubectl cheat sheet is built around. kubectl diff -fbefore applying anything into a cluster you did not set up yourself — it takes two seconds and prevents surprises.- For CKS, remember that
edit,replace --force, andapplyare all auditable API writes; knowing which fields a manager owns (managedFields) connects to least-privilege review. Interacting with the resulting objects is covered in kubectl exec, cp, port-forward & debug.
Practice the Reflex, Don’t Memorize the Flags
You will not remember this under a countdown clock by re-reading it — you remember it by doing it until the choice is automatic: seeing “already exists” and reaching for apply, seeing “immutable” and reaching for replace --force. That reflex is exactly what timed, task-based practice builds.
Sailor.sh’s KubeAstronaut mock exam bundle is built around this kind of hands-on, cross-certification practice — the same object-management tasks framed the way the CKA, CKAD, CKS, KCNA and KCSA present them, so you build the muscle memory once and carry it across all five CNCF exams. If you want a lighter warm-up first, the free Kubernetes practice lab for the CNCF exams is a good place to start drilling apply, create and replace against a real cluster.
Frequently Asked Questions
What is the difference between kubectl apply and kubectl create?
create makes a new object and errors if it already exists; it is not idempotent. apply creates the object if absent and updates it if present, using a three-way merge, so it is safe to run repeatedly. Use apply for anything you manage from a file over time.
When should I use kubectl replace instead of apply?
Use replace -f when you want a full overwrite with no merge, and replace --force -f when you must change an immutable field — it deletes and recreates the object. For normal updates to shared objects, prefer apply, which preserves fields set by controllers.
What does replace --force actually do?
It deletes the existing object and creates it again from your file. Expect a new UID and, for Pods, a restart. It is the standard workaround when the API rejects an in-place change with a “field is immutable” error.
What is the last-applied-configuration annotation?
It is a copy of the last manifest you applied, stored by client-side kubectl apply under kubectl.kubernetes.io/last-applied-configuration. Apply uses it as one input to its three-way merge so it knows which fields you previously managed and should now delete or keep.
What is Server-Side Apply and do I need it for the exam?
Server-Side Apply runs the merge on the API server and tracks per-field ownership in metadata.managedFields, raising conflicts when two managers fight over a field. You rarely type --server-side on a timed exam, but understanding field managers and conflicts is fair game on the KCNA and CKS.
Why did a field disappear after I ran kubectl apply?
Usually because the object was first created with create (no last-applied annotation) and then managed with apply, or because you removed the field from your file after previously applying it. Manage each object with one technique consistently to avoid this.
Which exams test these concepts?
The CKA, CKAD and CKS test them implicitly in every task where you create or change objects; the KCNA tests the declarative model and imperative-vs-declarative distinction as knowledge questions. All five appear in the KubeAstronaut bundle.
Conclusion
kubectl gives you three ways to manage an object, and the exam quietly rewards knowing which is which. Use imperative commands to move fast and to scaffold YAML; use apply to manage that YAML idempotently with a three-way merge that respects other actors; use create when you want a guaranteed-new object; and keep replace --force in your pocket for immutable-field changes. Manage each object with one mode for its whole life, preview risky changes with diff, and the whole family stops being a memorization exercise and becomes a reflex. Drill it against a live cluster until the right command is the one your fingers reach for automatically — that is what carries points across the CKA, CKAD, CKS, KCNA and KCSA.