YAML to JSON, and Back Again: A Practical Conversion Guide
How to convert YAML to JSON and JSON to YAML without losing data — why configs use YAML, why APIs want JSON, and the type-coercion traps that bite.
YAML to JSON, and Back Again: A Practical Conversion Guide
Every config file I touch is YAML. Every API I call wants JSON. That mismatch is the whole reason a YAML-to-JSON converter earns a permanent tab in my browser. The two formats describe the same data — maps, lists, scalars — but they were built for different readers, and translating between them is where small mistakes turn into a 400 Bad Request at 2 a.m.
This is a field guide to that translation: what changes structurally, why each format won where it did, and the type-coercion gotchas that quietly corrupt your data on the way through.
Why configs are YAML but APIs speak JSON
YAML was designed to be written and read by humans. Indentation instead of braces, comments with #, no commas trailing every line, anchors to avoid repeating yourself. Kubernetes, GitHub Actions, docker-compose, Ansible — they all chose YAML because a person edits these files by hand, and a person should be able to scan one without counting brackets.
JSON went the other way. It is a strict, unambiguous serialization format with exactly one way to write most things. No comments, no anchors, no significant whitespace. That rigidity is a feature for machines: every JSON parser on the planet agrees on what a document means, which is exactly what you want when a service receives a payload and has to act on it.
So the division of labor is natural. Humans author YAML; programs exchange JSON. The converter sits on the boundary. You write the friendly version, then flatten it to the strict version your tooling actually consumes.
What actually changes when you convert
The transformation is mechanical, and seeing it concretely makes the failure modes obvious. Three structural rules cover almost everything:
- YAML indentation becomes JSON braces. A nested map expressed by two-space indentation turns into nested
{ }objects. - YAML lists become JSON arrays. Lines starting with
-collapse into[ ]. - Unquoted scalars get type-inferred. A bare
42becomes a number,truebecomes a boolean, and — this is the trap — certain bare words become booleans you didn't ask for.
Here is a small worked example. Input YAML:
service: api-gateway
replicas: 3
debug: false
ports:
- 8080
- 8443
labels:
tier: backend
managed: yes
Run it through the converter and you get:
{
"service": "api-gateway",
"replicas": 3,
"debug": false,
"ports": [8080, 8443],
"labels": {
"tier": "backend",
"managed": "yes"
}
}
Notice three things. The indentation under labels: became a nested object. The - 8080 / - 8443 list became the array [8080, 8443]. And replicas: 3 became the number 3, not the string "3". The structure mapped over cleanly, but the values went through type inference — which is where you have to pay attention.
You can try this exact paste in the YAML to JSON converter and watch each line transform.
The type-coercion gotchas that bite
Look again at managed: yes in the example above. It stayed a string "yes", not the boolean true. That surprises people, and the history is worth knowing.
Old YAML 1.1 treated yes, no, on, and off as booleans. It also read true/false, True/False, and a pile of other spellings the same way. The modern YAML 1.2 spec dropped that — under 1.2, only true and false are booleans, and yes is just the three-letter string it looks like. The converter follows 1.2, so:
enabled: true→ JSONtrueenabled: yes→ JSON"yes"enabled: "true"→ JSON"true"(you quoted it, so it stays a string)
The lesson: if you want a real boolean, write true or false. If you genuinely mean the word "yes," you're fine either way, but never rely on yes/no to flip a flag. The infamous case is the "Norway problem" — a country list with NO for Norway, where NO got read as the boolean false and Norway vanished. Quoting it ("NO") makes it unambiguous.
Two more coercion traps:
- Quoted vs unquoted numbers.
version: 1.20parses as the number1.2(trailing zero gone), which breaks if you meant a version string. Writeversion: "1.20"to keep it textual. - Leading zeros and colons.
id: 007andtime: 22:30can be read as numbers or sexagesimals depending on the parser. When a scalar must stay literal, quote it.
The fix is always the same reflex: when a value's type matters, quote it. Unquoted means "let the parser decide," and the parser does not know your intent.
Indentation, comments, and the round trip
The other half of "and back again" is going JSON → YAML, and a couple of things don't survive a full round trip.
Comments are gone. JSON has no comment syntax. So every # this is the prod cluster line in your YAML is dropped the moment you convert to JSON. Convert that JSON back to YAML and the comments do not return — they were never in the JSON to begin with. If a comment carries real meaning, promote it into an actual key (_note: "prod cluster") before converting.
Tabs are illegal. The YAML spec forbids tab characters for indentation. A config copied out of an editor that auto-inserts tabs fails on the first indented line with a cryptic parse error. Set your editor to soft tabs (spaces), or let the converter's line-numbered error point you straight at the offending row.
Indent width is cosmetic, not semantic. Two spaces vs four spaces per level changes nothing about the meaning — pick one and stay consistent. Mixing widths under the same key (jobs: with two spaces here, four there) is the single most common reason a GitHub Actions workflow throws "did not find expected key."
Key order, for what it's worth, is preserved on a clean round trip — both the parser and JSON.stringify keep insertion order, so {"b":1,"a":2} stays b then a rather than getting sorted.
Keep secrets in the browser
Plenty of the YAML I convert is not innocent. A Kubernetes secret manifest, a CI config with an API token, a database URL with a password in it — these end up in converters all the time because that's where the config lives. Pasting any of that into a server-side web tool means your secret just took a trip through someone else's logs.
A good converter does the parsing entirely client-side. Nothing you paste leaves the tab; there's no upload, and the input is never written into the URL, so it can't leak through browser history, share links, or referrer headers. Close the tab and it's gone. That's the right default for anything carrying credentials — verify it before you paste a secret.yaml.
Wrapping up
Converting between YAML and JSON is mostly mechanical: indentation becomes braces, list items become arrays, scalars get type-inferred. The places it goes wrong are predictable — yes/no that aren't booleans, numbers that should have been strings, comments that evaporate, tabs that the spec rejects. Quote anything whose type matters, expect comments to disappear, and use a tool that keeps the whole thing in your browser.
Once your JSON is in hand, a JSON formatter tidies and validates it for the API call, and if you'd rather clean up the source side, a YAML formatter normalizes indentation before you ever convert.
Made by Toolora · Updated 2026-06-13