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.
- My Kubernetes cluster setup
- Generate the YAML for a service
- Generate the YAML for a deployment
- Export every resource in a namespace or the whole cluster
- Bash script to generate all the YAMLs for an existing cluster
- Clean the exported YAML so you can apply it again (kubectl neat, yq)
- Other output formats - json, jsonpath, custom-columns, kyaml
- Generate YAML from scratch with --dry-run=client
- Common errors and questions
- Conclusion
1. My Kubernetes cluster setup
- I have already set up my Kubernetes cluster with 1 master and 2 worker nodes, along with one
helloworlddeployment installed from a Helm chart. - Deployment :
deployment.apps/myreleasename-helloworld - 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 alldoes 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-resourceslists 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 -
- The above
kubectlcommand prints the YAML and the shell redirect saves it intoservice.yaml. -o yaml(long form--output=yaml) is the flag which does the work. It is available on everykubectl get, for every resource kind, including custom resources.- Substitute the service name and the namespace as per your need. Without
-n, kubectl uses the namespace of your current context, which isdefaultunless 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 -
--all-namespaces(short form-A) ignores the namespace of your context and lists everything.- The output is a single
kind: Listobject with anitems:array containing every service.kubectl applyunderstands 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 -
- Short names work too -
kubectl get deploy myreleasename-helloworld -o yaml. - 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. - A deployment export carries a big
status:block (replicas, conditions, observedGeneration) and the annotationdeployment.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 -
- Create a file called
generate-yaml.shand 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/"
- 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
- Here is the list of directories generated by the script, e.g. configmap, deployment.apps, secret, service, serviceaccount -

Here are all the YAMLs with their names -

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 -
Fields to remove before reapplying -
| Field | Why |
|---|---|
metadata.uid | Unique to the original object; apply into another cluster fails with a uid mismatch |
metadata.resourceVersion | Optimistic-locking counter; causes the object has been modified conflicts |
metadata.creationTimestamp, metadata.generation | Set by the server, ignored or rejected on create |
metadata.managedFields | Server-side apply bookkeeping, hundreds of noisy lines |
metadata.selfLink | Removed 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/revision | Stale 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 -
- Setup kubernetes on Ubuntu
- Setup Kubernetes on CentOs
- Setup HA Kubernetes Cluster with Kubespray
- Setup HA Kubernetes with Minikube
- Setup Kubernetes Dashboard for local kubernetes cluster
- Setup Kubernetes Dashboard On GCP(Google Cloud Platform)
- How to use Persistent Volume and Persistent Volume Claims in Kubernetes
- Deploy Spring Boot Microservice on local Kubernetes cluster
- Deploy Spring Boot Microservice on Cloud Platform(GCP)
- Setting up Ingress controller NGINX along with HAproxy inside Kubernetes cluster
- CI/CD Kubernetes | Setting up CI/CD Jenkins pipeline for kubernetes
- kubectl export YAML | Get YAML for deployed kubernetes resources(service, deployment, PV, PVC....)
- How to setup kubernetes jenkins pipeline on AWS?
- Implementing Kubernetes liveness, Readiness and Startup probes with Spring Boot Microservice Application?
- How to fix kubernetes pods getting recreated?
- How to delete all kubernetes PODS?
- How to use Kubernetes secrets?
- Share kubernetes secrets between namespaces?
- How to Delete PV(Persistent Volume) and PVC(Persistent Volume Claim) stuck in terminating state?
- Delete Kubernetes POD stuck in terminating state?
- Kubernetes IP Calculator - the free tool that sizes node subnets, Pod ranges and max pods per node for EKS, GKE and AKS