YAML to JSON converter
Convert YAML to JSON and JSON back to YAML in your browser, following YAML 1.2, with anchors and merge keys resolved, multi-document streams, and syntax errors reported by line and column.
Loading the YAML parser…
Comments and anchors are not part of the data, so they do not survive the trip. Merge keys and aliases are resolved into the values they stand for.
Convert YAML to JSON and JSON back to YAML in your browser, following YAML 1.2, with anchors and merge keys resolved, multi-document streams, and syntax errors reported by line and column.
On this page
How to use this tool#
- Pick a direction. YAML to JSON parses and converts; JSON to YAML goes the other way. Conversion runs as you type, so there is no button to press.
- Paste your document over the example. The example is there so you can see what the output looks like before you commit anything.
- Choose the output shape. Going to JSON you get 2 spaces, 4 spaces, tabs or minified. Going to YAML you get 2 or 4 spaces, and a choice of how much to quote.
- Read the messages under the output. A syntax error names the line and the column and shows you the line with a caret under the spot. Notes appear when something in the document does not survive the conversion cleanly, such as an anchor or a
.nan. - Use Swap to check a round trip. It moves the output into the input and flips the direction, so you can see what comes back.
The tool doubles as a YAML validator: if the document parses, the JSON appears; if it does not, you get the position of the first problem. Nothing is uploaded, so it is safe to paste a config that has secrets in it.
YAML and JSON are closer than they look#
The YAML 1.2 specification says of its own history that its "primary focus was making YAML a strict superset of JSON". That is why conversion in this direction is mostly mechanical: every JSON document is already a valid YAML document, and JSON's four scalar types (string, number, boolean, null) plus its two collections (object, array) all exist in YAML with the same meaning.
So converting YAML to JSON is not a translation between two data models. It is one data model written out in the other's syntax, minus the parts of YAML that JSON has no place to put.
# YAML JSON
name: api "name": "api"
port: 8080 "port": 8080
debug: true "debug": true
tags: [a, b] "tags": ["a", "b"]
limits: "limits": {
cpu: "500m" "cpu": "500m"
memory: 256Mi "memory": "256Mi"
}
notes: | "notes": "line one\nline two\n"
line one
line two
empty: "empty": nullYAML mappings become JSON objects, sequences become arrays, and plain scalars are resolved to a type by their shape: 8080 is a number, true is a boolean,null and an empty value are null, everything else is a string. Quoting a scalar in YAML always makes it a string, which is the escape hatch when the shape lies.
What does not survive the trip#
- Comments. JSON has none. Every
#line is gone, and there is no way to get it back from the JSON. - Anchors and aliases.
&nameand*nameare a reuse mechanism in the file, not a value. This tool resolves them, so the target is copied into every place that referred to it. The JSON is correct, but it is longer and the sharing is no longer visible. - Merge keys.
<<: *defaultsis folded into the map that used it, with any key written locally winning over the merged one. - Tags.
!!binarybecomes its base64 text and an explicit!!timestampbecomes an ISO 8601 string. An application-specific tag such as CloudFormation's!Refhas no meaning to a general parser, so the value is kept as plain text and the tool says so in a note. - Block scalar style. A literal block (
|) and a folded block (>) both become an ordinary JSON string with\nescapes. The text is preserved; the layout that produced it is not. - Key order, sometimes. This tool writes keys in the order they appear. Whether that order survives depends on what reads the JSON next: most languages keep object key order on parse, but neither the JSON nor the YAML specification promises it, so do not build anything on it.
defaults: &defaults
restart: unless-stopped
logging: json-file
web:
<<: *defaults
image: nginx
# becomes, in JSON:
# "web": { "restart": "unless-stopped", "logging": "json-file", "image": "nginx" }Values JSON cannot represent#
A handful of YAML values have no JSON equivalent at all. Silently dropping them is how data goes missing, so this tool converts them and tells you what it did.
.inf,-.infand.nanbecomenull. The JSON grammar has no token for them. Note that other converters differ here: Python'sjson.dumpswrites the literalsInfinityandNaN, which are not valid JSON and which a strict reader will reject.- Integers beyond 253 are written out in full, digit for digit, so nothing is lost in the file itself. JSON allows numbers of any length. The catch is on the reading side:
JSON.parseand most other readers turn them into doubles and round them. The tool warns when a document contains one. - Dates. Under YAML 1.2 a bare
2001-12-14is already a string, so it comes through untouched. Only an explicit!!timestamptag produces a date, and that becomes an ISO 8601 string. - Keys that are not strings. YAML lets a mapping key be a number, a boolean, null, or a whole collection. JSON object keys are always strings, so those keys are converted to text and the tool notes it.
- Duplicate keys are reported as an error, not quietly merged. The YAML specification says a mapping's keys must be unique, and a duplicate is almost always a copy and paste mistake. The output still shows you the result with the last value winning, so you can see what a lenient parser would have done.
The Norway problem: YAML 1.1 against YAML 1.2#
This tool follows YAML 1.2, with the core schema. That matters, because the older 1.1 rules are still in wide use and they resolve some plain scalars very differently.
The famous case is the ISO country code for Norway. Under YAML 1.1, y,yes, no, on and off and their capitalised forms are booleans. So a list of country codes turns Norway into false, while Namibia's NA stays a string.
# Country codes, the classic case.
countries:
- name: Norway
code: NO
- name: Namibia
code: NA
# Feature flags written the natural way.
telemetry: off
debug: noYAML 1.2 (this tool, and any 1.2 parser)
code: NO -> "NO" a string
telemetry: off -> "off" a string
YAML 1.1 (PyYAML 6.0.3, Ruby Psych 5.3.1)
code: NO -> False a boolean
telemetry: off -> False a booleanYAML 1.2's core schema cut the boolean set down to true and falseonly, and dropped two other 1.1 rules that surprise people just as much: a leading zero no longer means octal, and 12:30 is no longer a sexagesimal number.
# Read by PyYAML 6.0.3 / Ruby Psych 5.3.1, both YAML 1.1:
version: 0123 -> 83 leading zero means octal
start: 12:30 -> 750 in PyYAML: 12 * 60 + 30
start: 12:30 -> 45000 in Psych: 12.5 * 3600
released: 2001-12-14 -> a date object, not a string
# The same file read as YAML 1.2, here:
version: 0123 -> 123 plain decimal
start: 12:30 -> "12:30" a string
released: 2001-12-14 -> "2001-12-14" a stringThe numbers above are from actually running those parsers, not from the specification. Which parser you are feeding decides which set of rules applies:
- PyYAML (checked with 6.0.3) still applies the 1.1 rules in both
yaml.loadandyaml.safe_load:noisFalse,0123is 83,12:30is 750, and2001-12-14is adatetime.date. Singleyandnare the exception: PyYAML leaves those as strings. - Ruby's Psych (checked with 5.3.1) behaves the same way for booleans and octal, and reads
12:30as 45000 rather than 750, since it takes the rightmost group as seconds. - Go's
gopkg.in/yaml.v3(checked with v3.0.1) is a hybrid. Decoded into anany,nostays the string"no", but0123still comes out as 83 and2001-12-14as atime.Time. Decode the samenointo a field typedbooland it is accepted as false. - js-yaml, the other common JavaScript parser, does not have the Norway problem in any recent release:
nois a string in 3.15.2, 4.3.2 and 5.4.2 alike. Version 3 does apply the 1.1 number rules (0123is 83,12:30is 750); version 4 dropped them.
Indentation, and why tabs are banned#
YAML block structure is indentation. Keys in the same mapping must start in the same column, and nesting is any greater indentation. There is no closing bracket to correct a mistake, so an indentation slip changes the meaning of the document rather than breaking it, which is how you end up with a value silently attached to the wrong key.
Tabs are not allowed to do that job. The specification is explicit: "To maintain portability, tab characters must not be used in indentation, since different systems treat tabs differently." A tab inside a value is fine; a tab at the start of a line, where indentation is being counted, is a syntax error. This tool reports it as one, with the line number.
# Right: spaces, and the same amount for every key in a block.
server:
host: localhost
ports:
- 80
- 443
# Wrong: the second key is indented further than the first.
server:
host: localhost
port: 8080
# Wrong: a tab. YAML forbids tabs in indentation.
server:
host: localhostIf you paste YAML here and get a tab error you did not expect, your editor is expanding tabs visually. Turn on "show whitespace", or set the editor to insert spaces for.yaml and .yml files.
Multi-document files#
One YAML file can hold several documents, separated by ---. Kubernetes manifests use this constantly, and so do CI pipelines that ship more than one object per file.
apiVersion: v1
kind: Service
metadata:
name: api
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 2JSON has no equivalent separator, so a stream has to become something. This tool wraps the documents in a JSON array, one entry per document, in file order, and says so in a note under the output. An empty document between two separators becomesnull. A single document is not wrapped, so the common case stays plain.
Command-line tools do not all agree on this. Python's yaml.safe_load_all returns an iterator you would usually turn into a list before dumping it, which gives you the same array, while yq prints one JSON document after another unless you ask it to combine them. If the thing reading your JSON expects a single object, split the YAML first rather than converting the whole file.
A note on untrusted YAML#
YAML's tag mechanism was designed to let a parser build language-native objects, and some parsers historically wired that to arbitrary constructors. That is a remote code execution bug waiting to happen, not a theoretical risk.
PyYAML documents it plainly: "It is not safe to call yaml.load with any data received from an untrusted source! yaml.load is as powerful aspickle.load". Modern PyYAML makes it hard to get wrong by accident: in 6.0.3, calling yaml.load(text) with no second argument raisesTypeError: load() missing 1 required positional argument: 'Loader'. Useyaml.safe_load unless you have a specific reason not to. Ruby'sYAML.safe_load and Go's typed decoding are the equivalents elsewhere.
The second risk is cheaper to trigger: a small file can expand into an enormous one. Nested anchors, the "billion laughs" pattern, let a few hundred bytes of aliases become gigabytes once every reference is resolved. This tool caps alias resolution at 100 per document and stops with an error rather than filling your tab's memory.
This page parses data only. It never constructs an object from a tag, never evaluates anything, and makes no network call. The conversion happens in your browser, in JavaScript, after the page has loaded, so nothing you paste is sent anywhere. There is nowhere to send it: the site is static files with no backend. Disconnect from the network and the tool keeps working, which is the quickest way to prove it.
Converting on the command line#
yq
# yq v4 (github.com/mikefarah/yq), a single Go binary.
# YAML to JSON
yq -o=json input.yaml
# YAML to JSON on one line
yq -o=json -I=0 input.yaml
# JSON to YAML: set the input parser, YAML is the default output
yq -p=json input.json
# yq v3 used a different command shape (yq r / yq w), so check
# "yq --version" before copying a recipe from an old answer.Do not confuse it with jq, which reads JSON only, or with the older Pythonyq wrapper, which has its own flags.
Python
import json, sys, yaml
# YAML to JSON
print(json.dumps(yaml.safe_load(sys.stdin), indent=2))
# JSON to YAML
print(yaml.safe_dump(json.load(sys.stdin), sort_keys=False))$ printf 'a: 1\nb: [x, y]\n' | python3 -c \
'import json,sys,yaml; print(json.dumps(yaml.safe_load(sys.stdin), indent=2))'
{
"a": 1,
"b": [
"x",
"y"
]
}
# The other direction. PyYAML quotes "no" on the way out,
# because it would read it back as a boolean.
$ python3 -c 'import yaml; print(yaml.safe_dump({"a": "no"}))'
a: 'no'Node
// npm install yaml
import YAML from 'yaml';
import { readFileSync } from 'node:fs';
const text = readFileSync('input.yaml', 'utf8');
// YAML to JSON
console.log(JSON.stringify(YAML.parse(text), null, 2));
// JSON to YAML
console.log(YAML.stringify(JSON.parse('{"b":1,"a":"no"}')));
// b: 1
// a: no <- plain, because YAML 1.2 reads it back as a stringRuby
require 'yaml'
require 'json'
# YAML to JSON
puts JSON.pretty_generate(YAML.safe_load(File.read('input.yaml')))
# JSON to YAML
puts YAML.dump(JSON.parse('{"b":1,"a":"no"}'))
# ---
# b: 1
# a: 'no'Go
import (
"encoding/json"
"fmt"
"os"
"gopkg.in/yaml.v3"
)
func main() {
var v any
if err := yaml.NewDecoder(os.Stdin).Decode(&v); err != nil {
panic(err)
}
out, _ := json.MarshalIndent(v, "", " ")
fmt.Println(string(out))
}Questions people ask#
Can I convert JSON to YAML here too?
Yes. Switch the direction to JSON to YAML, or press Swap after a conversion. You get 2 or 4 space indentation and a choice of how much to quote. Because every JSON document is already valid YAML, the conversion cannot fail once the JSON parses; the interesting part is how much quoting to keep, which is what the quoting option controls.
Why did my YAML to JSON output lose the comments?
Because JSON does not have comments, and no converter can invent a place to keep them. If you need the comments, keep the YAML as the source of truth and generate the JSON from it, rather than converting once and switching formats.
Is this a YAML validator?
For syntax, yes. If the document parses, you get JSON; if it does not, you get the first error with its line and column and the offending line. It does not validate against a schema, so it cannot tell you that a Kubernetes manifest is missing spec.replicas. For that you want a schema-aware tool such as kubeconform, or your editor's YAML language server with the right schema attached.
My file is valid YAML but a tool rejects it. Why?
Usually a version mismatch, and usually in one of the three places above: a bareno or off, a leading zero, or a date. Convert the file here to see what a 1.2 parser makes of it, then quote whatever you did not intend to be typed.
Does the order of keys change?
Not here. Keys come out in the order they appear in the source. Whether it stays that way after something else parses the JSON is not guaranteed by either specification, so treat mappings as unordered when it matters.
What happens to a very large file?
It is converted in your browser like anything else, which means the limit is your machine rather than an upload size. A one megabyte document is comfortable. The output box shows the first 200,000 characters to keep scrolling smooth, while copy gives you the whole thing.
Which YAML version does this follow?
YAML 1.2 with the core schema, the current specification. A document that opens with a%YAML 1.1 directive is parsed with the 1.1 rules instead, since that is what the document asks for.
Related tools
Convert identifiers and text to camelCase, PascalCase, snake_case, SCREAMING_SNAKE_CASE, kebab-case, Train-Case, dot.case, path/case and four more at once, one line at a time, with acronyms and digits split the way style guides expect.
Convert a Unix timestamp to a date and back, with the unit detected from the number, any IANA time zone, ISO 8601, RFC 2822, relative time and ISO week, plus the current epoch ticking live.
Percent-encode and decode URLs and query strings, with encodeURIComponent, encodeURI, strict RFC 3986 and form encoding, plus a breakdown of the query parameters.