What happens when YAML becomes JSON?
Converting YAML to JSON means parsing the YAML into plain data (mappings, sequences and scalars) and writing that data out in JSON syntax. Comments, anchors and formatting choices disappear, and every unquoted value has to be resolved to a type. Those type rules decide whether 1.10 stays a version string or becomes the number 1.1.
The converter uses the js-yaml library (version 5.4.2) with its default schema, the YAML 1.2 core schema described in the YAML 1.2.2 specification. The JSON is printed with two-space indentation.
A worked example
service: checkout
replicas: 3
enabled: yes
image: &img
registry: ghcr.io
tag: "1.4"
sidecar:
image: *img
ports:
- 8080
- 8443
notes: |
Deployed by CI.
becomes:
{
"service": "checkout",
"replicas": 3,
"enabled": "yes",
"image": {
"registry": "ghcr.io",
"tag": "1.4"
},
"sidecar": {
"image": {
"registry": "ghcr.io",
"tag": "1.4"
}
},
"ports": [
8080,
8443
],
"notes": "Deployed by CI.\n"
}
The alias *img was expanded into a second copy of the image block. enabled: yes stayed a string, because YAML 1.2 doesn't treat yes as a boolean. The literal block (|) kept its trailing newline.
How unquoted values are typed
These results come straight from the converter:
| YAML | JSON | Why |
|---|---|---|
country: NO |
"NO" |
Only true/false are booleans in YAML 1.2 |
version: 1.10 |
1.1 |
Looks like a float, so trailing zeros go |
quoted: "1.10" |
"1.10" |
Quotes always force a string |
zip: 01234 |
1234 |
Leading zeros are ignored for decimal integers |
octal: 0o14 |
12 |
0o is the 1.2 octal prefix |
hex: 0x1F |
31 |
Hexadecimal integer |
date: 2026-10-27 |
"2026-10-27" |
No timestamp type in the core schema |
nothing: ~ and empty: |
null |
Both are null |
inf: .inf |
null |
JSON has no Infinity, so it prints null |
url: http://x.com:8080/a |
"http://x.com:8080/a" |
A colon not followed by a space is just text |
The safe habit is to quote anything that must stay a string: version numbers, postcodes, IDs with leading zeros, phone numbers. Integers longer than 15 or 16 digits also lose precision, since they're stored as JavaScript numbers.
Things that stop the conversion
The error message includes a line and column plus a small excerpt with a caret under the problem. The usual causes:
- Unclosed brackets or quotes.
b: [1, 2fails with "unexpected end of the stream within a flow collection". - Tabs in indentation. YAML forbids them; the error is "tab characters must not be used in indentation".
- Custom tags. CloudFormation's
!Refor!GetAtt, and also!!binaryand!!set, fail with "unknown scalar tag" or "unknown mapping tag". - Duplicate keys. Two
a:keys in one mapping give "duplicated mapping key". - Complex keys. A sequence used as a key (
? [a, b]) can't become a JSON property name.
Two inputs that other tools reject do convert here. A stream of several ----separated documents becomes a JSON array with one item per document, and a file containing only comments converts to null, because it holds no data.
If you only want to know whether a file parses, the YAML validator runs the same parser without producing output.
Merge keys are applied
Many configuration files share settings with a merge key, like this:
defaults: &defaults
adapter: postgres
port: 5432
development:
<<: *defaults
database: app_dev
port: 5433
That merge key belongs to YAML 1.1's type repository, not to the 1.2 core schema, but the converter enables it because so many real files depend on it. The anchored keys are copied into development, and a key written in the mapping itself wins over the merged one, so port is 5433:
"development": {
"adapter": "postgres",
"port": 5433,
"database": "app_dev"
}
A list of aliases (<<: [*base, *extra]) merges several mappings, with earlier ones taking precedence. To keep a literal << key instead, quote it: "<<": value.
Multi-line strings
YAML has two block styles for long text, and they convert differently. Take two indented lines, "word one" and "word two". Under a literal block (|) every line break is kept, giving "word one\nword two\n". Under a folded block (>) the lines are joined with a space, giving "word one word two\n": one line with a single newline at the end. Both styles keep one trailing newline by default. Add a chomping indicator (|- or >-) to drop it, or |+ to keep every trailing blank line. If a JSON consumer compares strings exactly, that final \n is a common source of "the values look identical but don't match" bugs.
Key order is preserved: properties appear in the JSON in the same order as in the YAML, which makes it easy to compare the two side by side.
After converting
YAML 1.2 was designed so that JSON documents are also valid YAML, which means you can paste JSON into this tool and get it back reformatted. More often the next step goes the other way: tidy the result with the JSON formatter, or query parts of it with the JSONPath tester. For editing YAML with syntax highlighting, use the online YAML editor.
Last updated