kubectl get YAML - How to Export the YAML of Deployed Kubernetes Resources (Deployment, Service, All Resources, Clean Reusable Manifests)


In this post we are going to see how to get the YAML of deployed Kubernetes resources - a single deployment or service, and then every pvc, configmap, ingress, service, secret, deployment, statefulset, hpa, job and cronjob in the cluster in one go.

Most of the time we create deployments and services from YAML files. But sooner or later you need to go the other way - somebody created a resource with kubectl create or from the dashboard and never saved the file, you inherited a cluster with no repository, or you want to copy an application from one cluster to another. kubectl get -o yaml is the answer, and this post covers both the basic command and the part most tutorials skip - how to turn the export into a clean manifest you can actually apply again.

  1. My Kubernetes cluster setup
  2. Generate the YAML for a service
  3. Generate the YAML for a deployment
  4. Export every resource in a namespace or the whole cluster
  5. Bash script to generate all the YAMLs for an existing cluster
  6. Clean the exported YAML so you can apply it again (kubectl neat, yq)
  7. Other output formats - json, jsonpath, custom-columns, kyaml
  8. Generate YAML from scratch with --dry-run=client
  9. Common errors and questions
  10. Conclusion



1. My Kubernetes cluster setup

  1. I have already set up my Kubernetes cluster with 1 master and 2 worker nodes, along with one helloworld deployment installed from a Helm chart.
  2. Deployment : deployment.apps/myreleasename-helloworld
  3. Service : service/myreleasename-helloworld

Here are the complete details of my current cluster

1kubectl get all
 1NAME                                           READY   STATUS    RESTARTS   AGE
 2pod/myreleasename-helloworld-7c4dd5588-wc6js   1/1     Running   1          8d
 3
 4NAME                               TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
 5service/kubernetes                 ClusterIP   10.233.0.1     <none>        443/TCP   13d
 6service/myreleasename-helloworld   ClusterIP   10.233.58.70   <none>        80/TCP    8d
 7
 8NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
 9deployment.apps/myreleasename-helloworld   1/1     1            1           8d
10
11NAME                                                 DESIRED   CURRENT   READY   AGE
12replicaset.apps/myreleasename-helloworld-7c4dd5588   1         1         1       8d

Note - kubectl get all does not show everything. ConfigMaps, Secrets, PersistentVolumeClaims, Ingresses, ServiceAccounts and custom resources are not part of "all". That matters a lot for this post, because those are exactly the things you forget to export. kubectl api-resources lists every kind your cluster knows about.



2. Let's generate the YAML for the "service"

Use the following kubectl command to get the YAML of the service running with the name myreleasename-helloworld inside the cluster -

1kubectl get service myreleasename-helloworld -n default -o yaml > service.yaml

Few points to notice -
  1. The above kubectl command prints the YAML and the shell redirect saves it into service.yaml.
  2. -o yaml (long form --output=yaml) is the flag which does the work. It is available on every kubectl get, for every resource kind, including custom resources.
  3. Substitute the service name and the namespace as per your need. Without -n, kubectl uses the namespace of your current context, which is default unless you changed it.

Here is what the export of a service looks like - notice the fields which were not in the original manifest -

 1apiVersion: v1
 2kind: Service
 3metadata:
 4  annotations:
 5    meta.helm.sh/release-name: myreleasename
 6    meta.helm.sh/release-namespace: default
 7  creationTimestamp: "2026-10-01T09:12:44Z"          # added by the API server
 8  labels:
 9    app.kubernetes.io/instance: myreleasename
10    app.kubernetes.io/managed-by: Helm
11    app.kubernetes.io/name: helloworld
12  managedFields: [...]                                 # server-side apply bookkeeping
13  name: myreleasename-helloworld
14  namespace: default
15  resourceVersion: "488121"                           # internal version counter
16  uid: 2a9d6c54-1f0c-4a8e-9f0e-0c8a7a5b1234           # unique id of THIS object
17spec:
18  clusterIP: 10.233.58.70                              # assigned by the cluster
19  clusterIPs:
20  - 10.233.58.70
21  internalTrafficPolicy: Cluster
22  ipFamilies:
23  - IPv4
24  ipFamilyPolicy: SingleStack
25  ports:
26  - name: http
27    port: 80
28    protocol: TCP
29    targetPort: http
30  selector:
31    app.kubernetes.io/instance: myreleasename
32    app.kubernetes.io/name: helloworld
33  sessionAffinity: None
34  type: ClusterIP
35status:                                                # current state, not desired state
36  loadBalancer: {}

Everything marked with a comment is runtime data added by Kubernetes. It is fine for reading and for backups, but it will cause problems if you try to kubectl apply this file into another cluster - we fix that in Section 6.


2.1 How to generate the YAML for all the services in the Kubernetes cluster

To generate a single YAML for all the services across every namespace -

1kubectl get service --all-namespaces -o yaml > all-service.yaml

Few points to notice -
  1. --all-namespaces (short form -A) ignores the namespace of your context and lists everything.
  2. The output is a single kind: List object with an items: array containing every service. kubectl apply understands a List, so you can apply it back in one go.


3. Let's generate the YAML for "deployment"

Getting the YAML for a deployment is exactly the same as for a service -

1kubectl get deployment myreleasename-helloworld -n default -o yaml > deployment.yaml

Few points to notice -
  1. Short names work too - kubectl get deploy myreleasename-helloworld -o yaml.
  2. You can combine kind and name in one argument - kubectl get deployment/myreleasename-helloworld -o yaml, which is the form the script in Section 5 uses.
  3. A deployment export carries a big status: block (replicas, conditions, observedGeneration) and the annotation deployment.kubernetes.io/revision. Both go away in the clean-up step.

3.1 How to generate the YAML for all the deployments in the Kubernetes cluster

1kubectl get deploy --all-namespaces -o yaml > all-deployment.yaml

The same pattern works for any kind - kubectl get configmap -A -o yaml, kubectl get ingress -A -o yaml, kubectl get pvc -A -o yaml. And you can ask for several kinds at once, comma separated -

1kubectl get deploy,svc,configmap,ingress -n default -o yaml > app.yaml

4. Export every resource in a namespace or the whole cluster

The one-liner people usually want is "give me the YAML of everything in this namespace". Because get all misses so much, list the kinds explicitly -

1kubectl get deploy,sts,ds,svc,ingress,configmap,secret,pvc,sa,hpa,job,cronjob,networkpolicy \
2  -n default -o yaml > namespace-default.yaml

For custom resources (Helm releases are not CRDs, but things like Certificate, ServiceMonitor, Kafka are), add them by name, or discover them -

1# every namespaced kind the cluster knows about
2kubectl api-resources --verbs=list --namespaced -o name
3
4# export all of them for one namespace (slow on a big cluster, but complete)
5kubectl get $(kubectl api-resources --verbs=list --namespaced -o name | paste -sd, -) \
6  -n default -o yaml > namespace-default-everything.yaml

Two kinds you probably do not want in that file - events (pure noise) and endpoints / endpointslices (managed by the service controller). And one you must handle with care - secrets, because the export contains the base64 values in plain sight. Never commit that file to git.



5. Bash script to generate all the YAMLs for an existing cluster

In point 2 and point 3 we exported one file per kind. But is there a way to generate one file per resource, in a folder per kind, for the whole cluster?

The answer is YES - with a small shell script -

  1. Create a file called generate-yaml.sh and save the following script into it -
 1#!/usr/bin/env bash
 2# Export one YAML file per resource, in a directory per kind,
 3# for every namespace in the cluster.
 4
 5set -euo pipefail
 6
 7KINDS="pvc,configmap,serviceaccount,secret,ingress,service,deployment,statefulset,daemonset,hpa,job,cronjob"
 8OUT="${1:-k8s-export}"
 9
10for ns in $(kubectl get namespaces -o jsonpath='{.items[*].metadata.name}'); do
11  for n in $(kubectl get -o name -n "$ns" $KINDS 2>/dev/null); do
12    # n looks like "deployment.apps/myreleasename-helloworld"
13    mkdir -p "$OUT/$ns/$(dirname "$n")"
14    kubectl get -o yaml -n "$ns" "$n" > "$OUT/$ns/$n.yaml"
15  done
16done
17
18echo "Exported to $OUT/"
  1. Make it executable and run it -
1chmod +x generate-yaml.sh
2./generate-yaml.sh            # writes into ./k8s-export
3./generate-yaml.sh my-backup  # or a directory of your choice
  1. Here is the list of directories generated by the script, e.g. configmap, deployment.apps, secret, service, serviceaccount -

list of directories generated by the shell script for the YAMLs of deployed Kubernetes resources

Here are all the YAMLs with their names -

all the YAMLs generated for the deployed Kubernetes resources

Compared with the version of this script in the video, this one loops over namespaces (the original only exported the current one), skips kinds a namespace does not have, and includes daemonset. Add any custom resource kinds you use to KINDS.

If your applications are installed with Helm, there is a shortcut for each release - helm get manifest <release> -n <namespace> prints the exact rendered YAML Helm applied, without any runtime fields. And helm get values <release> gives you the values, which is what you actually want to keep in git.



6. Clean the exported YAML so you can apply it again (kubectl neat, yq)

This is the part which separates a backup from a reusable manifest. Here is what comes back from the API server and what to do with it -

kubectl get -o yaml returns the live object with runtime fields; strip them before reapplying

Fields to remove before reapplying -

FieldWhy
metadata.uidUnique to the original object; apply into another cluster fails with a uid mismatch
metadata.resourceVersionOptimistic-locking counter; causes the object has been modified conflicts
metadata.creationTimestamp, metadata.generationSet by the server, ignored or rejected on create
metadata.managedFieldsServer-side apply bookkeeping, hundreds of noisy lines
metadata.selfLinkRemoved in Kubernetes 1.20, you still see it in old exports
status (whole block)Current state, not desired state; the controller rebuilds it
spec.clusterIP, spec.clusterIPs (Services)Assigned by the cluster; a different cluster will reject the IP
spec.nodeName (Pods)Pins the pod to a node that does not exist elsewhere
spec.volumeName (PVCs)Binds to a specific PV in the old cluster
annotations: kubectl.kubernetes.io/last-applied-configuration, deployment.kubernetes.io/revisionStale bookkeeping

Option 1 - kubectl neat. The easiest tool for this is the kubectl-neat plugin, installed through krew. It removes all of the above and more -

1# install once
2kubectl krew install neat
3
4# use it on any export
5kubectl get deployment myreleasename-helloworld -o yaml | kubectl neat > deployment-clean.yaml
6kubectl get -n default deploy,svc,configmap -o yaml | kubectl neat > app-clean.yaml

Option 2 - yq. If you cannot install plugins (CI runners, locked-down laptops), yq does the same with one filter -

1kubectl get deployment myreleasename-helloworld -o yaml \
2  | yq 'del(.metadata.uid, .metadata.resourceVersion, .metadata.generation,
3            .metadata.creationTimestamp, .metadata.managedFields, .metadata.selfLink,
4            .metadata.annotations."kubectl.kubernetes.io/last-applied-configuration",
5            .metadata.annotations."deployment.kubernetes.io/revision",
6            .status)' > deployment-clean.yaml

For a kind: List export (the -A output), prefix the paths with .items[].

Option 3 - the old --export flag. If you remember kubectl get --export, it did part of this job. It was deprecated in kubectl 1.14 and removed in 1.18, so on any current cluster you get error: unknown flag: --export. Use neat or yq.

Then verify the clean file applies without errors, without touching the cluster -

1kubectl apply --dry-run=server -f deployment-clean.yaml
2kubectl diff -f deployment-clean.yaml      # shows what would change versus the live object

7. Other output formats - json, jsonpath, custom-columns, kyaml

-o yaml is one of many output formats of kubectl get. The ones I use every week -

 1# JSON - same content as yaml, for jq
 2kubectl get deployment myreleasename-helloworld -o json | jq '.spec.template.spec.containers[].image'
 3
 4# jsonpath - pull a single value, perfect for scripts
 5kubectl get svc myreleasename-helloworld -o jsonpath='{.spec.clusterIP}{"\n"}'
 6kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.podIP}{"\n"}{end}'
 7
 8# custom-columns - a table of exactly the fields you want
 9kubectl get pods -o custom-columns='NAME:.metadata.name,IMAGE:.spec.containers[0].image,NODE:.spec.nodeName'
10
11# name - "kind/name" only, which is what the export script loops over
12kubectl get all -o name
13
14# wide - the default table plus node, IP and nominated node
15kubectl get pods -o wide

Newer kubectl versions also offer -o kyaml, a stricter YAML dialect that is easier to diff and parse. The full list is in the kubectl get reference - json, yaml, kyaml, name, go-template, go-template-file, template, templatefile, jsonpath, jsonpath-as-json, jsonpath-file, custom-columns, custom-columns-file, wide.


8. Generate YAML from scratch with --dry-run=client

A lot of people searching for "kubectl export yaml" actually want the opposite - a starting manifest for a resource that does not exist yet. The create commands can print YAML instead of creating the object -

 1# a deployment manifest
 2kubectl create deployment helloworld --image=rahulwagh17/kubernetes:jhooq-k8s-helloworld \
 3  --replicas=2 --port=8080 --dry-run=client -o yaml > deployment.yaml
 4
 5# a service manifest for it
 6kubectl expose deployment helloworld --port=80 --target-port=8080 --type=ClusterIP \
 7  --dry-run=client -o yaml > service.yaml
 8
 9# a configmap from a file, a secret from literals
10kubectl create configmap app-config --from-file=app.properties --dry-run=client -o yaml > configmap.yaml
11kubectl create secret generic db-creds --from-literal=password=changeme --dry-run=client -o yaml > secret.yaml

--dry-run=client means nothing is sent to the cluster; -o yaml prints the object kubectl would have created. This is how I start every manifest - generate, then edit. These generated files are already clean (no uid, no status), so they apply anywhere. I keep the ones I use most in my Kubernetes cheat sheet.


9. Common errors and questions

1. error: unknown flag: --export - Removed in kubectl 1.18. Use kubectl neat or the yq filter from Section 6.

2. Error from server (NotFound): deployments.apps "x" not found - Wrong namespace. Add -n <namespace> or find it with kubectl get deploy -A | grep x.

3. Applying the export fails with metadata.resourceVersion: Invalid value: ... must be specified for an update or the object has been modified - You applied an uncleaned export. Strip resourceVersion and uid.

4. Applying a Service fails with spec.clusterIP: Invalid value ... field is immutable or provided IP is already allocated - Remove clusterIP and clusterIPs from the export so the new cluster assigns its own.

5. The exported Pod YAML does not survive a restart - A Pod export is a snapshot of one pod. Export the owner instead (Deployment, StatefulSet, DaemonSet). If you are unsure who owns a pod, this post on pods getting recreated shows how to find the owner.

6. The Secret values look like gibberish - They are base64, not encrypted. echo <value> | base64 -d decodes them. Treat the export as sensitive, and read Kubernetes secrets for the proper way to manage them.

7. I want the YAML of a Helm release - helm get manifest <release> -n <ns> and helm get values <release> -n <ns>.

8. I want the YAML the way it was originally applied, not the live object - If it was applied with kubectl apply, the original is stored in the kubectl.kubernetes.io/last-applied-configuration annotation - kubectl apply view-last-applied deployment/myreleasename-helloworld.


10. Conclusion

kubectl get <kind> <name> -o yaml is all it takes to export the YAML of any deployed Kubernetes resource, -A and comma-separated kinds scale it to a namespace or the whole cluster, and the script in Section 5 gives you one file per resource. The part to remember is that the export is the live object, not your manifest - strip the runtime fields with kubectl neat or yq before you apply it anywhere else, keep Secrets out of git, and for anything you are creating new, start from kubectl create ... --dry-run=client -o yaml.

(Reference - I prepared this blog post after reading this GitHub issue and StackOverflow discussion, and the kubectl get reference has every flag used above.)


Learn more On Kubernetes -

  1. Setup kubernetes on Ubuntu
  2. Setup Kubernetes on CentOs
  3. Setup HA Kubernetes Cluster with Kubespray
  4. Setup HA Kubernetes with Minikube
  5. Setup Kubernetes Dashboard for local kubernetes cluster
  6. Setup Kubernetes Dashboard On GCP(Google Cloud Platform)
  7. How to use Persistent Volume and Persistent Volume Claims in Kubernetes
  8. Deploy Spring Boot Microservice on local Kubernetes cluster
  9. Deploy Spring Boot Microservice on Cloud Platform(GCP)
  10. Setting up Ingress controller NGINX along with HAproxy inside Kubernetes cluster
  11. CI/CD Kubernetes | Setting up CI/CD Jenkins pipeline for kubernetes
  12. kubectl export YAML | Get YAML for deployed kubernetes resources(service, deployment, PV, PVC....)
  13. How to setup kubernetes jenkins pipeline on AWS?
  14. Implementing Kubernetes liveness, Readiness and Startup probes with Spring Boot Microservice Application?
  15. How to fix kubernetes pods getting recreated?
  16. How to delete all kubernetes PODS?
  17. How to use Kubernetes secrets?
  18. Share kubernetes secrets between namespaces?
  19. How to Delete PV(Persistent Volume) and PVC(Persistent Volume Claim) stuck in terminating state?
  20. Delete Kubernetes POD stuck in terminating state?
  21. Kubernetes IP Calculator - the free tool that sizes node subnets, Pod ranges and max pods per node for EKS, GKE and AKS