json:yaml

Kubernetes JSON to YAML converter

Convert a manifest to YAML and find out whether it is actually ready to commit. Missing apiVersion, leftover status blocks and managedFields are all flagged.

JSON
YAML

      
Paste JSON to convert.

Conversion happens in this browser tab. Nothing is uploaded, logged, or stored.

Kubernetes® is a registered trademark of The Linux Foundation. This is an independent tool, not affiliated with or endorsed by The Linux Foundation or the Kubernetes project. See trademarks.

What this page checks that a plain converter does not

Any converter will turn manifest JSON into YAML. This one also reads the document as a Kubernetes object and tells you when it is syntactically fine but will not do what you want:

  • Missing apiVersion or kind. kubectl apply rejects an object without both, with an error that does not name the file helpfully when you are applying a directory.
  • Missing metadata.name, unless generateName is set.
  • Server-populated fields. If the document carries status, metadata.uid, resourceVersion, creationTimestamp, generation, selfLink or managedFields, it came from a live cluster and should be cleaned before it goes into a repository. See below.
  • kind: List. A list of objects has to be split into separate YAML documents with --- before it can be applied.

The status bar turns amber for these rather than red, because the conversion succeeded — the warning is about the manifest, not the syntax.

Why manifests arrive as JSON

Almost nobody writes Kubernetes JSON by hand. It shows up because something emitted it:

  • kubectl get deploy checkout-api -o json, when someone needs to capture what is actually running.
  • Terraform's kubernetes_manifest resource and the kubernetes provider, which speak JSON internally.
  • Pulumi, CDK8s, and other tools that generate manifests from code.
  • API responses from the cluster itself, or from an admission controller log.
  • Helm's --dry-run -o json output when you are checking what a chart will render.

In every case the destination is the same: a .yaml file that a human will review in a pull request. YAML is what the ecosystem's documentation, examples, and tooling assume, and it is the only one of the two that can carry a comment explaining why a replica count is what it is.

Cleaning a live object before committing it

Cleaning the manifest is the step people miss, and it is the reason a converted manifest sometimes fails to apply to a fresh cluster. Anything you pull with -o json contains fields the API server added, not fields you authored.

FieldWhy it must go
statusObserved state. Meaningless in a manifest, and enormous.
metadata.uidIdentifies that one object on that one cluster.
metadata.resourceVersionOptimistic-concurrency token. Applying it can fail with a conflict.
metadata.creationTimestampSet by the server; often serialises as null, which some validators reject.
metadata.generationServer-maintained counter.
metadata.managedFieldsServer-side apply bookkeeping. Frequently longer than the manifest itself.
metadata.selfLinkRemoved from the API entirely in 1.21; harmless but dead.
spec.clusterIP on a ServiceAllocated by the cluster. A hard-coded IP will not apply elsewhere.
Default-injected fieldsThings like terminationMessagePath and dnsPolicy that you never set. Harmless, but they add noise to every future diff.

The quickest way to strip them is kubectl-neat:

kubectl get deploy checkout-api -o json | kubectl neat > deployment.json

Or with jq, if you would rather not add a plugin:

kubectl get deploy checkout-api -o json \
  | jq 'del(.status,
            .metadata.uid,
            .metadata.resourceVersion,
            .metadata.creationTimestamp,
            .metadata.generation,
            .metadata.managedFields,
            .metadata.selfLink,
            .metadata.annotations["kubectl.kubernetes.io/last-applied-configuration"])'

Paste the result above, and the warnings should clear.

Converting several objects at once

Asking for more than one object gives you a List, not a stream:

kubectl get deploy,svc -n payments -o json    # -> { "kind": "List", "items": [...] }

Converted directly, that produces one YAML document with an items array under it. It is valid YAML, and kubectl apply does accept a List — but it is not what anyone wants in a repository, because the objects cannot be reviewed, moved, or applied individually.

Split it first:

# one YAML document per object, separated by ---
kubectl get deploy,svc -n payments -o json \
  | jq -c '.items[]' \
  | while read -r o; do echo "---"; echo "$o" | yq -P; done > manifests.yaml

# or write one file per object
kubectl get deploy -o json | jq -c '.items[]' | while read -r o; do
  name=$(echo "$o" | jq -r '.metadata.name')
  echo "$o" | yq -P > "$name.yaml"
done

Where converted manifests go wrong

Environment variable values must be strings

Every value in an env entry has to be a string. JSON's "2500" is already correct, and the converter keeps the quotes for exactly this reason. Write value: 2500 by hand and the API server rejects the object with a type error, because it wanted a string and got an integer.

Quantities that look like numbers

cpu: 500m and memory: 512Mi are fine unquoted, since neither parses as a number. But a whole-CPU request written as cpu: 1 is an integer, and while Kubernetes accepts it, mixing 1 and "1" across files makes diffs noisy. Pick one and stay with it.

Version tags that lose a zero

An image tag inside a string is safe. A chart value like version: 1.10 is not: unquoted, YAML reads it as the float 1.1 and your deployment pulls the wrong thing. The silent failures table lists the rest of this family.

Tabs

If you hand-edit the converted output and your editor inserts a tab, the manifest stops parsing entirely. YAML forbids tabs in indentation — see the indentation rules. Set indent_style = space for *.yaml in your .editorconfig.

The output is valid YAML but invalid Kubernetes

This tool checks structure, not schema. It cannot know that spec.replicas must be an integer or that your CRD requires a particular field. Before committing, ask the cluster:

kubectl apply --dry-run=client -f deployment.yaml   # schema, no cluster contact
kubectl apply --dry-run=server -f deployment.yaml   # full validation, including admission

Doing it without a browser

# single object, straight from the cluster to a file
kubectl get deploy checkout-api -o yaml > deployment.yaml

# JSON you already have
yq -P -o=yaml deployment.json > deployment.yaml

# clean and convert in one pass
kubectl get deploy checkout-api -o json | kubectl neat | yq -P > deployment.yaml

kubectl get -o yaml is the obvious route when you have cluster access, and it is the right one. This page is for the times you do not: a manifest pasted into a ticket, output from a CI log, a chart rendered by someone else, or JSON from a system that has no kubectl anywhere near it.

Manifests do not leave your browser

A manifest is a map of your infrastructure. Even with Secrets held elsewhere, it names your registry, your internal hostnames, your namespaces, your service accounts, and the exact image versions you are running — which is a list of the CVEs you are exposed to, for anyone who cares to look.

None of that is transmitted here. The conversion and the manifest checks both run in JavaScript inside this tab, on your machine. There is no upload step, no server that could log it, and nothing is kept when you close the page.

Questions people ask

Why not just use kubectl get -o yaml?
You should, when you have cluster access — it is the shorter route. This page is for the times you do not: a manifest pasted into a ticket, JSON from a CI log, output from Terraform or Pulumi, or a chart someone else rendered.
Why does the converter warn about managedFields and status?
Because the document came from a live cluster rather than from your repository. Those fields are set by the API server, they are often longer than the manifest itself, and committing them produces diffs that change every time anything reconciles.
My manifest is kind: List. What do I do?
Split it into one document per object, separated by ---. kubectl does accept a List, but the objects cannot then be reviewed, moved or applied individually. The command to split it is on this page.
Why does the converter keep the quotes on some environment variables?
Because every value in an env entry has to be a string. Unquoted, "2500" would become the integer 2500 and the API server would reject the object with a type error.
Does this validate against the Kubernetes schema?
No. It checks structure — apiVersion, kind, metadata.name, and fields that should not be committed. For real schema validation run kubectl apply --dry-run=client, or --dry-run=server to include admission controllers.
Is my manifest uploaded anywhere?
No. Conversion and the manifest checks both run in JavaScript in this browser tab. A manifest names your registry, hostnames, namespaces and image versions, which is not something to hand to an unfamiliar website.