Manage Kubernetes Resources with apply, edit, patch and replace

Learn kubectl apply, edit, patch, replace, diff, and dry-run with practical Deployment examples and guidance on declarative versus live updates.

Published

Updated

Read time 10 min read

Reviewed byDeepak Prasad

kubectl apply edit patch and replace workflows for updating Kubernetes Deployments
Tested on Rocky Linux 10.2 (Red Quartz) workstation
Package kubectl 1.36.3
Applies to Linux or macOS shell with kubectl configured; any Kubernetes cluster
Cert prep CKA · CKAD
Lab environment Multi-node kubeadm cluster with containerd — install Kubernetes with kubeadm
Privilege Normal user (no sudo required on the workstation)
Scope kubectl apply, diff, client and server dry-run, edit, strategic merge, JSON merge, and JSON Patch, patch files, replace and replace --force, server-side apply overview, manifest drift, comparison tables, and troubleshooting. Does not cover basic get/create/delete, full YAML anatomy, Kustomize overlays, Deployment rollout rollback, Helm, GitOps, or managed-fields internals.
Related guides Kubernetes labels and selectors

This walkthrough uses one web Deployment in the kubectl-lab namespace. You apply a starter manifest, then update it with apply, diff, dry-run, edit, patch, and replace so you can pick the right tool for each situation.

If kubectl syntax, namespaces, or YAML basics are new, start with kubectl command examples before this chapter.


Different methods to update Kubernetes Resource

Kubernetes objects change over time. The command you choose depends on whether you maintain YAML on disk, need a quick live edit, or want to replace the whole object.

Command Best suited for
kubectl apply Declaratively create or update resources from manifests
kubectl edit Make an immediate interactive change to a live object
kubectl patch Change selected fields without supplying the full object
kubectl replace Replace the existing object using a complete manifest
kubectl diff Preview differences before applying
--dry-run Validate or preview a command without making the normal change

The sections below walk through each method on the same Deployment.


Prepare the Example Deployment

Create a namespace and a Deployment with two replicas, one nginx container, matching selector labels, and a version label on the Pod template.

Save namespace.yaml:

yaml
apiVersion: v1
kind: Namespace
metadata:
  name: kubectl-lab

Save deployment.yaml:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: kubectl-lab
  labels:
    app: web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
        version: v1
    spec:
      containers:
        - name: nginx
          image: nginx:1.25.4
          ports:
            - containerPort: 80

Apply the namespace first, then the Deployment:

bash
kubectl apply -f namespace.yaml
bash
kubectl apply -f deployment.yaml

Sample output:

output
namespace/kubectl-lab created
deployment.apps/web created

Confirm the initial shape:

bash
kubectl get deployment web -n kubectl-lab

Sample output:

output
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
web    0/2     2            0           0s

UP-TO-DATE shows how many replicas use the Deployment's latest desired Pod template. It does not mean those Pods are already scheduled or Ready. READY may lag briefly while images pull.

Every update example in this article targets this same web Deployment.


Update Resources with kubectl apply

kubectl apply creates a resource when it does not exist and updates it when the manifest changes. Treat the YAML file as the maintained source of configuration for declarative workflows.

Re-run apply against an unchanged file:

bash
kubectl apply -f deployment.yaml

When the maintained configuration has not changed, kubectl normally reports unchanged. configured indicates that kubectl submitted an update.

Edit the maintained manifest

Edit deployment.yaml on disk:

  • Set replicas to 3
  • Change the image to nginx:1.27.0
  • Change the Pod-template label version from v1 to v2

Preview changes with kubectl diff

kubectl diff compares your manifest against the live object without applying it:

bash
kubectl diff -f deployment.yaml

Sample output (trimmed):

output
diff -u -N /tmp/LIVE-316227394/apps.v1.Deployment.kubectl-lab.web /tmp/MERGED-4285196381/apps.v1.Deployment.kubectl-lab.web
--- /tmp/LIVE-316227394/apps.v1.Deployment.kubectl-lab.web
+++ /tmp/MERGED-4285196381/apps.v1.Deployment.kubectl-lab.web
@@ -15,7 +15,7 @@
   uid: ecbd21e9-b47d-4f3f-aa6c-a3cc90b09ece
 spec:
   progressDeadlineSeconds: 600
-  replicas: 2
+  replicas: 3
   revisionHistoryLimit: 10
@@ -29,10 +29,10 @@
     metadata:
       labels:
         app: web
-        version: v1
+        version: v2
     spec:
       containers:
-      - image: nginx:1.25.4
+      - image: nginx:1.27.0

kubectl diff returns 0 when no differences exist, 1 when differences are found, and a value greater than 1 for an error. This matters in scripts and CI pipelines.

Lines prefixed with - show current cluster values. Lines with + show what the manifest would set. The command exits after printing the diff; it does not change the Deployment.

Validate with client and server dry-run

--dry-run validates or previews a command without persisting the normal change.

Client dry-run builds the object locally:

bash
kubectl apply -f deployment.yaml --dry-run=client -o yaml

Sample output (trimmed):

output
replicas: 3
        version: v2
      - image: nginx:1.27.0

kubectl processes the file on your workstation and prints the resulting object. The API server does not persist it.

Server dry-run sends the request to the API server for validation:

bash
kubectl apply -f deployment.yaml --dry-run=server -o yaml

The output shape matches client dry-run for this Deployment, but admission controllers and validation run on the server. Use server dry-run when you need API-level checks before a real apply.

Mode Uses API server validation Persists change
client No No
server Yes No

Apply the updated manifest

Apply the edited file:

bash
kubectl apply -f deployment.yaml

Sample output:

output
deployment.apps/web configured

Verify the live spec:

bash
kubectl get deployment web -n kubectl-lab -o jsonpath='replicas={.spec.replicas} image={.spec.template.spec.containers[0].image} version={.spec.template.metadata.labels.version}{"\n"}'

Sample output:

output
replicas=3 image=nginx:1.27.0 version=v2

The Deployment controller rolls out a new ReplicaSet when the Pod template changes.

Apply multiple files

apply accepts several inputs:

  • Multiple files: kubectl apply -f namespace.yaml -f deployment.yaml
  • A directory: kubectl apply -f ./manifests/
  • Standard input: kubectl apply -f - (pipe YAML into kubectl)

Kustomize overlays use kubectl apply -k on a directory with kustomization.yaml. That path is covered in Kubernetes Kustomize; this article stays on plain -f manifests.

Server-side apply

Server-side apply lets the API server track field ownership and detect conflicts when several actors manage one object. Conflicting changes are normally rejected rather than automatically resolved unless ownership is deliberately forced.

bash
kubectl apply --server-side -f deployment.yaml

Sample output:

output
deployment.apps/web serverside-applied

Use server-side apply when multiple actors need explicit field ownership. Actors should normally manage distinct fields; attempting to change a differently valued field owned by another manager causes a conflict unless ownership is deliberately forced. This article does not dive into managed-fields internals.


Edit a Live Resource with kubectl edit

kubectl edit opens the current object in your editor and submits changes when you save.

bash
kubectl edit deployment web -n kubectl-lab

kubectl fetches the live Deployment, opens it in $KUBE_EDITOR or $EDITOR, and applies your edits when the editor exits successfully. The local deployment.yaml file is not updated automatically.

Change spec.replicas from 3 to 2, save the file, and close the editor.

bash
kubectl get deployment web -n kubectl-lab -o jsonpath='replicas={.spec.replicas}{"\n"}'

Sample output:

output
replicas=2

After a successful edit, deployment.yaml still contains replicas: 3, demonstrating manifest drift.

Configure the editor

Set the editor before running edit:

bash
export KUBE_EDITOR=nano

EDITOR is used when KUBE_EDITOR is unset.

When to use kubectl edit

kubectl edit fits fast lab changes, temporary troubleshooting, and small interactive updates. Avoid it when Git-managed YAML must remain the single source of truth—record important edits back into the manifest and apply from there.


Patch Selected Resource Fields

kubectl patch changes only the fields you specify instead of sending the complete object.

Strategic merge patch

Strategic merge is the default patch type for supported built-in resources such as Deployments.

Scale replicas:

bash
kubectl patch deployment web -n kubectl-lab -p '{"spec":{"replicas":4}}'

Sample output:

output
deployment.apps/web patched

Confirm:

bash
kubectl get deployment web -n kubectl-lab -o jsonpath='replicas={.spec.replicas}{"\n"}'

Sample output:

output
replicas=4

Change the container image with the same patch type:

bash
kubectl patch deployment web -n kubectl-lab \
  -p '{"spec":{"template":{"spec":{"containers":[{"name":"nginx","image":"nginx:1.27.1"}]}}}}'
bash
kubectl get deployment web -n kubectl-lab -o jsonpath='image={.spec.template.spec.containers[0].image}{"\n"}'

Sample output:

output
image=nginx:1.27.1

Strategic merge merges lists such as containers by name rather than replacing the entire list blindly.

Use kubectl explain when you need the exact field path for a resource type.

JSON merge patch

JSON merge patch treats object fields as merges and replaces whole lists when you send a list in the patch:

bash
kubectl patch deployment web -n kubectl-lab --type=merge -p '{"metadata":{"labels":{"tier":"frontend"}}}'

Sample output:

output
deployment.apps/web patched

Check the new label:

bash
kubectl get deployment web -n kubectl-lab -o jsonpath='tier={.metadata.labels.tier}{"\n"}'

Sample output:

output
tier=frontend

JSON Patch

JSON Patch (RFC 6902) sends explicit operations:

bash
kubectl patch deployment web -n kubectl-lab --type=json -p='[{"op":"replace","path":"/spec/replicas","value":3}]'

Sample output:

output
deployment.apps/web patched

One replace operation targets /spec/replicas with value 3. Use JSON Patch when you need precise path-based edits.

Patch using a file

Large patches belong in a file:

Save patch.yaml:

yaml
spec:
  template:
    metadata:
      labels:
        track: stable

Apply it:

bash
kubectl patch deployment web -n kubectl-lab --patch-file patch.yaml

Sample output:

output
deployment.apps/web patched

Verify:

bash
kubectl get deployment web -n kubectl-lab -o jsonpath='track={.spec.template.metadata.labels.track}{"\n"}'

Sample output:

output
track=stable

CRD limitation

Strategic merge patch is not supported for custom resources. For CRDs use --type=merge or --type=json, or update the CR manifest and apply.


Replace a Resource from a Manifest

kubectl replace submits a complete replacement object. The resource must already exist, and the manifest must include the live object's metadata.resourceVersion. Kubernetes recommends exporting the complete live object before replacing it.

Wait for the current rollout to finish, then export the live Deployment:

bash
kubectl rollout status deployment/web -n kubectl-lab --timeout=120s
bash
kubectl get deployment web -n kubectl-lab -o yaml > deployment-replace.yaml

Edit deployment-replace.yaml and set:

yaml
spec:
  replicas: 2

You can also remove live-only tier and track labels to demonstrate that fields omitted from a complete replacement are removed.

Replace the object:

bash
kubectl replace -f deployment-replace.yaml

Sample output:

output
deployment.apps/web replaced

Confirm:

bash
kubectl get deployment web -n kubectl-lab -o jsonpath='replicas={.spec.replicas}{"\n"}'

Sample output:

output
replicas=2

Fields omitted from the replacement manifest can be removed or reset compared to the live object. replace is a poor fit when several tools manage different fields on the same object—apply preserves fields kubectl does not own.

Force replacement

When an immutable field blocks an update, replace --force deletes and recreates the object. Keep the clean source manifest for this example:

bash
kubectl replace --force -f deployment.yaml

replace --force deletes and recreates the Deployment with a new UID. Its ReplicaSets and Pods are consequently replaced, and application availability can be interrupted while the recreated workload becomes Ready. Use --force only when recreation is acceptable.


Compare apply, edit, patch and replace

Requirement Recommended command
Maintain resources from YAML kubectl apply
Preview manifest changes kubectl diff
Test validation without saving --dry-run=server
Make a quick interactive change kubectl edit
Change one or two selected fields kubectl patch
Submit a complete replacement object kubectl replace
Delete and recreate from a manifest kubectl replace --force only when required

Understand Manifest Drift

kubectl edit and kubectl patch change the live object but not your local YAML. The cluster and the file can diverge.

If you apply an older manifest after a live patch, kubectl reapplies whatever the file still defines and can overwrite the manual change. Record important edits in the declarative source file. Run kubectl diff before apply when drift is possible.

This article does not cover GitOps reconciliation; the same drift principle applies whenever the file and cluster disagree.


Common Problems

Symptom Likely cause Fix
kubectl apply overwrites an earlier manual change Local manifest still defines a different value Update the YAML to match the desired state, or revert the live change before apply
kubectl edit reports the object was modified Another update occurred while the editor was open Close without saving, fetch the latest object, and edit again
Patch changes the wrong list item Wrong patch type or list merge behavior Use strategic merge for built-in types with named list keys; verify with kubectl explain
Strategic merge patch fails for a custom resource CRDs do not support strategic merge Use --type=merge or --type=json
kubectl replace reports the resource does not exist Object was never created Use kubectl apply or create the resource first
kubectl replace fails with a resource version conflict Exported manifest is stale or missing metadata.resourceVersion Re-export the live object with kubectl get -o yaml before editing
An immutable field cannot be changed Field is fixed after creation Revert the field or recreate with replace --force when appropriate
Live resource changes but source YAML does not edit or patch skipped the manifest Copy the change into the maintained file

What's Next


References


Summary

You prepared one web Deployment in kubectl-lab and updated it with the main kubectl change commands. kubectl apply remained the default for maintained YAML: edit the file, diff when you want a preview, dry-run when you want validation, then apply. kubectl edit and kubectl patch handled quick live edits and small field changes without opening the full manifest.

The main pitfall is manifest drift. Interactive edits and patches change the cluster immediately but not your Git copy. A later apply from stale YAML can undo them. Keep the declarative file aligned with production intent and run diff before apply when several people touch the same object.

For overlay-based layouts use Kubernetes Kustomize. For rollout status, history, and rollback after image changes, continue with Deployments and rolling updates.


Frequently Asked Questions

1. What is the difference between kubectl apply and kubectl replace?

kubectl apply creates or updates a resource from a maintained manifest. Default client-side apply uses the last-applied configuration annotation, while --server-side uses API-server field ownership. kubectl replace submits a complete replacement object. Use apply for normal declarative management.

2. When should I use kubectl patch instead of kubectl apply?

Use patch when you need to change one or two fields on a live object without editing the full manifest file, such as scaling replicas or swapping a container image during troubleshooting. Keep long-term changes in your YAML and apply from there.

3. What is the difference between dry-run client and dry-run server?

Client dry-run builds the object locally without calling the API server for normal persistence. Server dry-run sends the request to the API server for validation and admission checks but does not persist the change.

4. Why does kubectl apply overwrite my kubectl edit change?

kubectl edit updates the live object but not your local YAML. The next kubectl apply reapplies whatever the file still defines, which can revert the interactive edit.

5. Can I use strategic merge patch on a custom resource?

No. Strategic merge patch applies to supported built-in API types. For custom resources use JSON merge patch with --type=merge, JSON Patch with --type=json, or update the CR manifest and apply.

6. When should I use kubectl replace --force?

Only when an immutable field blocks an in-place update and you accept deleting and recreating the object. Recreation changes object identity and can interrupt running Pods until the replacement is ready.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)