kubectl diff

Diff the live cluster state against the configuration that would be applied. A dry-run comparison tool for safe deployments.

kubectl diff -f FILENAME [flags]

Common Flags

FlagShortDescription
-f--filenameFilename, directory, or URL containing the configuration to diff
-R--recursiveProcess the directory used in -f recursively
-l--selectorFilter by label selector
--field-managerName of the manager used to track field ownership
--force-conflictsIf true, server-side apply force conflicts

Examples

Diff a single manifest against live state

kubectl diff -f deployment.yaml

Diff an entire directory

kubectl diff -f manifests/

Diff with kustomize output

kubectl kustomize overlays/staging | kubectl diff -f -

Diff a Helm template

helm template my-release chart/ | kubectl diff -f -

Diff recursively through subdirectories

kubectl diff -f manifests/ -R

When to Use kubectl diff

kubectl diff shows you exactly what would change if you ran kubectl apply. It compares your local manifest against the live cluster state and outputs a unified diff. This is essential for safe deployments, code reviews, and CI/CD pipelines.

Basic Usage

kubectl diff -f deployment.yaml

The output looks like a standard unified diff:

 apiVersion: apps/v1
 kind: Deployment
 metadata:
   name: my-app
 spec:
   replicas: 3
-  replicas: 3
+  replicas: 5
   template:
     spec:
       containers:
       - name: app
-        image: my-app:v1.2.0
+        image: my-app:v1.3.0

Lines prefixed with - show the current live state, and + shows what the new state would be.

Exit Codes

The exit codes are meaningful and designed for scripting:

| Exit Code | Meaning | |-----------|---------| | 0 | No differences — cluster matches local manifests | | 1 | Differences exist — apply would make changes | | >1 | An error occurred (e.g., invalid YAML, connection failure) |

kubectl diff -f deployment.yaml
if [ $? -eq 0 ]; then
  echo "No changes to apply."
elif [ $? -eq 1 ]; then
  echo "Changes detected — review and apply."
else
  echo "Error occurred."
fi

CI/CD Integration

In deployment pipelines, diff provides visibility before apply:

#!/bin/bash
# Generate the diff
DIFF_OUTPUT=$(kubectl diff -f manifests/ 2>&1)
EXIT_CODE=$?

if [ $EXIT_CODE -eq 0 ]; then
  echo "No changes to deploy."
  exit 0
elif [ $EXIT_CODE -eq 1 ]; then
  echo "Changes to be applied:"
  echo "$DIFF_OUTPUT"
  # Post diff as a comment on the PR for review
  kubectl apply -f manifests/
else
  echo "Error running diff: $DIFF_OUTPUT"
  exit 1
fi

Using with Kustomize

Diff works seamlessly with kustomize and Helm:

# Kustomize
kubectl kustomize overlays/production | kubectl diff -f -

# Helm
helm template my-release ./chart --values values-prod.yaml | kubectl diff -f -

Piping through stdin (-f -) lets you diff generated manifests without writing temporary files.

Detecting Configuration Drift

Use diff to detect when live resources have been modified outside of your GitOps workflow:

# Check if any resources have drifted
kubectl diff -f manifests/
# If exit code is 1, someone modified resources directly

In a GitOps setup, any differences indicate drift — either from manual kubectl edits, admission webhook mutations, or controller-applied defaults.

Handling Server-Side Defaults

Kubernetes often adds default values to resources (e.g., default container resource limits, service account mounts). These appear in diff output even if you didn't change them. To reduce noise:

# Use server-side apply field manager to track ownership
kubectl diff -f deployment.yaml --field-manager=my-pipeline --force-conflicts

Server-side apply with field managers means diff only shows fields you own, reducing false positives from server-set defaults.

Comparing Directories

For multi-file deployments:

# Diff all files in a directory
kubectl diff -f manifests/

# Recursively diff subdirectories
kubectl diff -f manifests/ -R

# Diff only specific resources by label
kubectl diff -f manifests/ -l app=frontend

Permissions Required

kubectl diff requires the same permissions as kubectl get for the resources being diffed. Specifically:

  • get on the resource types being compared
  • list if diffing multiple resources

If you lack permissions, the diff fails with a forbidden error. This is important to consider when setting up service accounts for CI/CD pipelines.

Limitations

  • Diff does not show resources that exist in the cluster but are absent from your manifests (i.e., it won't detect orphaned resources).
  • New resources appear as entirely new content in the diff.
  • Diff sets the KUBECTL_EXTERNAL_DIFF environment variable if you want to use an external diff tool like dyff for better YAML-aware output:
export KUBECTL_EXTERNAL_DIFF="dyff between --omit-header"
kubectl diff -f deployment.yaml

Interview Questions About This Command

How do you preview what changes kubectl apply would make?
kubectl diff -f <file> compares the local manifest against the live cluster state and shows the differences in unified diff format.
What exit codes does kubectl diff return?
Exit code 0 means no differences. Exit code 1 means there are differences. Exit code >1 means an error occurred.
How does kubectl diff help in CI/CD pipelines?
It can be used as a gate to review changes before apply, or to generate change reports. Exit code 1 indicates changes are pending.

Common Mistakes

  • Treating exit code 1 as an error — it simply means differences exist, which is expected when deploying changes.
  • Not using diff before apply in production, missing unintended configuration drift.
  • Forgetting that diff requires read access to the cluster — it fetches live state for comparison.

Related Commands