KYAML: Kubernetes YAML Without the Norway Problem
Kubernetes is promoting KYAML, a strict subset of YAML that any parser accepts. It kills type coercion and indentation bugs without a migration.
Key takeaways
- KYAML is a strict subset of YAML that kubectl can emit with -o kyaml, enabled by default since Kubernetes 1.35.
- It uses braces, brackets and double-quoted string values, so values like NO or 1.10 cannot be silently coerced and indentation stops mattering.
- Every KYAML file is valid YAML, so adopting it needs no tooling migration.
On this page
KYAML is a strict subset of YAML (braces, brackets, always-quoted string values) that kubectl emits with -o kyaml, on by default since Kubernetes 1.35. Adopt it for generated and reviewed manifests: NO and 1.10 can no longer be coerced, indentation stops mattering, and every KYAML file is still valid YAML, so nothing else in your tooling changes.
Verified against
Kubernetes 1.37 (1.37.2) and kubectl with KYAML in beta since 1.35, against the kubernetes.io KYAML encoding reference, the v1.35 release notes and the Kubernetes blog's KYAML pretty-printing guide. Checked October 2026.
It will not become your default format, and it will not validate your schema, but as a low-risk hardening step it is hard to argue against.
The bug KYAML exists to kill
YAML lets you write a string without quotes, and then guesses its type. That is how the "Norway problem" got its name: the country code NO parses as boolean false in YAML 1.1 parsers. The same guessing turns 1.10 into the float 1.1, and a value like 0755 into an octal number. None of these fail loudly. The manifest applies, and the wrong value ends up in your cluster.
Here is a ConfigMap most people would write without a second thought:
apiVersion: v1
kind: ConfigMap
metadata:
name: flags
data:
country: NO
version: 1.10
Any parser that resolves 1.10 as a number hands you 1.1: the trailing zero is gone, and nothing warns you. Your tool chain may handle NO more kindly than a YAML 1.1 parser does, but you should not have to know which parser sits at each step between your editor and the API server. If your app reads version and expects 1.10, this is a production incident that starts as a clean diff.
What KYAML actually changes
Per the kubernetes.io KYAML reference and KEP-5295, KYAML is flow style only: {} for objects, [] for lists, and every string value double-quoted. It allows trailing commas, so a diff touches one line when you append, and a --- header distinguishes it from JSON at a glance. Comments are allowed, which is the reason we prefer it to converting everything to JSON. Keys stay unquoted in the documented examples.
The same ConfigMap as KYAML:
{
apiVersion: "v1",
kind: "ConfigMap",
metadata: {
name: "flags",
},
data: {
country: "NO",
version: "1.10",
},
}
That is the shape kubectl create configmap flags --from-literal=country=NO --from-literal=version=1.10 --dry-run=client -o kyaml produces. The types are no longer a guess, because a quoted string is a string in every parser. Whitespace stops carrying meaning too, so a bad merge or a Helm nindent slip cannot change the structure of the document.
Getting KYAML out of what you already have
The documented path is the output format. kubectl get configmap flags -o kyaml prints any live object as KYAML, and --dry-run=client -o kyaml does the same for objects you generate. For files already in Git, the Kubernetes blog's KYAML guide points to two yamlfmt tools. The one shipped in sigs.k8s.io/yaml converts a file or a whole directory and can show a diff instead:
go install sigs.k8s.io/yaml/yamlfmt@latest
yamlfmt -o=kyaml -d cm.yaml # show what would change
yamlfmt -o=kyaml cm.yaml > cm.kyaml.yaml
Google's yamlfmt added a dedicated kyaml formatter in v0.21.0 and also runs as a pre-commit hook, which suits teams that already lint YAML in CI.
On versions: KYAML arrived as an opt-in alpha in Kubernetes 1.34 behind KUBECTL_KYAML=true, and graduated to beta, enabled by default, in 1.35. You still have to ask for it with -o kyaml; setting KUBECTL_KYAML=false turns it off. If you are pinned to a 1.34 client, export the variable first. On 1.36 and later you can make it the default for kubectl get with kubectl kuberc set --section defaults --command get --option output=kyaml.
Prove nothing changed before you commit
Do not take "valid YAML" on faith when you convert a file. Compare what your tools actually parse. Kustomize gives us a cheap, cluster-free way to do it, because it renders both files through the same parser. If the unquoted original was being coerced, the diff looks like this:
for d in a b; do printf 'resources:\n - cm.yaml\n' > $d/kustomization.yaml; done
diff <(kubectl kustomize a) <(kubectl kustomize b)
4c4
< version: 1.1
---
> version: "1.10"
That diff is the point. A conversion that is truly behavior-preserving produces an empty diff, and one that fixes a latent coercion bug produces exactly the lines you need to review. Run it on every converted manifest in a PR. For Helm output, pipe helm template into a directory with a kustomization.yaml and diff the same way, which fits how Helm and Kustomize already compose.
One caution: KYAML does not rescue a Helm template that emits broken YAML in the first place. It is a serialization style for objects, not a fix for the templating step in front of them.
What not to expect
KYAML is not the default output. kubectl get -o yaml still prints conventional YAML, and the Kubernetes blog says there are currently no plans to make KYAML the default output format, so teams can adopt it selectively. It also has no schema awareness. A KYAML file with replicas: "3" is perfectly legal KYAML and will still be rejected or misread by the API server, so you still need kubectl apply --dry-run=server or a validator in CI. Finally, a file that mixes conventions is no worse than before, but you only get the benefit once you commit to the format for a given directory. The release notes for Kubernetes 1.37 are a reminder of how fast the surrounding tooling moves, so pin your client version when you rely on any of this.
Questions people ask
What is the Norway problem in YAML?
YAML 1.1 parsers treat several unquoted words, including NO, no, off and yes, as booleans. The country code for Norway, NO, therefore parses as false. The same implicit typing turns 1.10 into the number 1.1 and can read 0755 as octal. Quoting the value fixes it, and KYAML enforces quoting for every string value, so the coercion cannot happen.
How do I output KYAML with kubectl?
Add -o kyaml to any kubectl get or to a client-side dry run, for example kubectl get deployment my-app -o kyaml. It has been beta and enabled by default since Kubernetes 1.35. On a 1.34 client, set KUBECTL_KYAML=true first, because the format was opt-in alpha there. The flag is still required: plain -o yaml keeps printing conventional block-style YAML.
Can kubectl apply KYAML files?
Yes. Every KYAML file is valid YAML, so kubectl apply -f, Helm, Kustomize and any other YAML parser accept it unchanged, including older kubectl versions that cannot emit KYAML. That compatibility is the main design goal: you can convert one directory at a time, and conventional YAML and KYAML manifests can coexist in the same repository.
The decision, concretely
- Do you generate manifests with scripts or
kubectland commit the output? Emit KYAML with-o kyaml: stable diffs, no coercion, no indentation drift. - Do you hand-write and hand-review base manifests? Leave them alone until a coercion bug bites, then quote the offending value and move on.
- Are you converting an existing repo? Convert one directory, run the rendered diff above, and merge only if the parsed output matches or the differences are bugs you wanted fixed.
- Do you need schema safety? KYAML does not give it to you. Keep server-side dry-run or a schema validator in CI.
The call we'd make
Use KYAML for anything a machine writes and a human reviews, which is exactly where silent type changes hurt most, and gate every conversion with a rendered diff. Keep hand-authored YAML if your team is happy with it, because nothing forces you to move and the two coexist cleanly. Pin your kubectl version so -o kyaml behaves the same on every laptop and runner.
Sources
Cite this article
Kiril Urbonas (2026). KYAML: Kubernetes YAML Without the Norway Problem. DevOpsNess. Updated 2026-10-31. https://www.devopsness.com/blog/kyaml-kubernetes-yaml-without-the-norway-problem
[KYAML: Kubernetes YAML Without the Norway Problem](https://www.devopsness.com/blog/kyaml-kubernetes-yaml-without-the-norway-problem) (Kiril Urbonas, DevOpsNess, updated 2026-10-31)
More from DevOps
Explore more articles in this category
Gheist: Stolen GitHub Tokens Are Dumping Actions Secrets Past Log Masking. Hunt for ci-sync Branches
An automated tool is using stolen GitHub tokens to plant ci-sync branches whose workflow prints every secret base32-encoded, grabs the log and deletes the run. How to hunt for it across an org, what to rotate, and the controls that stop the next one.
Argo CD CVE-2026-113708: Read-Only Users Can Run Code on the Repo-Server. Upgrade to 3.4.10+
Three CVSS 9.9 Argo CD repo-server bugs can be reached by anyone with Application get, the permission most teams hand to every viewer. Fixed versions, the v2 and 3.3 support cliff, and the RBAC and config checks to run today.
CVE-2026-111497 "Broccoli2Shell": One Brotli Bug in Node.js, Envoy and Istio. Patch Node First
An out-of-bounds write in Google's Brotli decoder, now on CISA's KEV list, reaches Node.js through zlib and Envoy and Istio through the Brotli decompressor filter. Fixed versions, cluster-wide checks and what to block until you patch.
You might have missed
Evergreen posts worth revisiting.