JSON to YAML Converter
Paste JSON, get YAML a strict parser will accept — quoting and all.
YAML 1.2 style quoting: strings that could be read as numbers, booleans or nulls are quoted so they stay strings. Nothing leaves your browser.
Converting JSON to YAML without breaking the config
YAML is a superset of JSON, so in the strictest sense any JSON file is already valid YAML and you could rename the extension and walk away. Nobody does that, because the whole point of YAML is that a human has to read it during an incident at two in the morning. The real job of a converter is turning braces and commas into indentation while making sure every value keeps the type it had in the JSON — and that second half is where hand conversion goes wrong.
This tool parses your input with the browser's own JSON parser, then walks the resulting tree and emits block-style YAML. Objects become indented mappings, arrays become dash lists, and every scalar is checked against a list of patterns that would change its meaning if left bare. Nothing is uploaded; the conversion runs entirely in the page.
Worked example: a small Kubernetes-style deployment
Take this JSON, which is close to what a Helm template spits out: a name, a replica count, two ports and an environment block where the values are strings.
Input: {"name":"web-app","replicas":2,"ports":[80,443],"env":{"DEBUG":"false","REGION":"no"}}
With a 2 space indent the output is six lines. The scalar treatment differs on every single one:
| YAML line | Why it looks like that |
|---|---|
| name: web-app | Plain string, no special characters, so no quotes are needed. |
| replicas: 2 | JSON number stays a number — quoting it here would break the schema. |
| ports: | Array key on its own line; the items follow, indented. |
| - 80 | Dash plus space. The indent under a key is your chosen 2 or 4 spaces. |
| - 443 | Same rule; numeric items are never quoted. |
| env: | Nested object becomes a nested mapping one level deeper. |
| DEBUG: "false" | The JSON value was the string "false", so it is quoted to stay a string. |
| REGION: "no" | Same reason, and the more dangerous one — see below. |
Feed the unquoted version into a YAML 1.1 loader and DEBUG becomes the boolean false. Your container then gets the string "False" or "0" depending on the language runtime, environment variables being strings by definition, and you spend an hour wondering why debug logging never turns off.
The Norway problem, in one line
YAML 1.1 resolves y, Y, yes, no, on, off, true and false — in any capitalisation — to booleans. A list of ISO country codes written as GB, US, FR, NO therefore loads as GB, US, FR, false. This is known as the Norway problem, and it has bitten enough teams that YAML 1.2 dropped the y/n/on/off shortcuts entirely. The catch is that many parsers still in production, including PyYAML's default loader, follow the 1.1 rules. Emitting "no" with quotes costs two characters and removes the whole class of bug, so this converter always quotes strings that match a boolean-ish word, look like a number, look like null or a tilde, start with an indicator character such as - ? : , [ ] { } # & * ! | > ' " % @, or contain a colon followed by a space.
Two spaces or four?
YAML does not care, as long as you are consistent and never use tabs — a literal tab character for indentation is a parse error in every conformant parser. Convention decides for you in practice. Kubernetes manifests, docker-compose files, GitHub Actions workflows and Ansible playbooks are all published with 2 spaces, and most linters ship with that default. Four spaces show up in older Ruby and Java projects and in documents with shallow nesting where the extra width aids scanning. Pick 2 if the file is going anywhere near a Kubernetes cluster or a CI pipeline; the diff noise of converting later is not worth it. Sequence items add one more wrinkle: this converter indents dashes under their parent key, which is the style kubectl and the Kubernetes docs use, and both indented and non-indented dashes parse identically.
Migrating a config file, end to end
The most common reason people search for a JSON to YAML converter is a migration: an application that read config.json now wants config.yaml, or a serverless project is moving from a JSON template to a YAML one. The reliable sequence is convert, read, then verify. Convert here, read the output for values that changed shape — version numbers such as 1.10 are a classic, because as a JSON string "1.10" it must stay quoted or YAML will read the number 1.1 and drop your patch release — and then verify by loading the YAML in the tool that will consume it. If you have Python to hand, python -c "import yaml,json,sys; json.dump(yaml.safe_load(open('config.yaml')), sys.stdout)" round-trips it back to JSON so you can diff against the original. A clean diff means the conversion preserved every type.
Multiline strings are the other thing worth checking. A JSON string containing newline escapes is emitted here as a literal block using the pipe character, which is far more readable than one enormous quoted line — useful for embedded scripts, certificates or SQL. When the string ends without a trailing newline the block is written with a strip indicator so the value round-trips exactly; when the shape cannot be represented safely as a block, the converter falls back to a quoted single line rather than guessing.
What this converter deliberately does not do
It does not go backwards. Turning YAML into JSON means implementing or trusting a full YAML parser, complete with anchors, aliases, merge keys, custom tags and multi-document streams, and unsafe YAML loaders have a long history of remote code execution bugs. One direction, done carefully, is the safer product.
It does not invent anchors or aliases. If the same block appears five times in your JSON it appears five times in the YAML, because JSON has no shared-reference concept to detect. Add &anchor and *alias by hand if you want the deduplication. It also cannot carry comments, since JSON has none to carry, and it does not reorder or sort keys — insertion order from your JSON is preserved so that a diff against the original stays readable. Duplicate keys are impossible to preserve for the same reason: JSON.parse keeps the last one, exactly as your JSON consumer already did.
Sources & further reading
Frequently asked questions
Why does the converter put quotes around no and on?
YAML 1.1 parsers read y, n, yes, no, on and off as booleans, so an unquoted no silently becomes false. The classic casualty is Norway, whose country code NO turns into false in a list of country codes. Quoting every string that looks like a boolean keeps the value a string in both YAML 1.1 and 1.2 parsers.
Can I keep comments when converting?
JSON has no comment syntax, so there is nothing to carry over — anything you wrote as a fake comment key is converted as a normal key. Add YAML comments with # after converting. If your source file had JavaScript-style comments it was JSONC, not JSON, and you need to strip them before pasting.
Does this also convert YAML back to JSON?
No, and that is deliberate. Parsing arbitrary YAML safely is a much larger job than emitting it: anchors, aliases, merge keys, tags and multiple documents all have to be handled, and careless YAML loaders have caused real security incidents. This tool only goes one way, JSON to YAML.
Are anchors and aliases created for repeated blocks?
No. Repeated objects are written out in full every time, because JSON has no concept of a shared reference. If you want &anchor and *alias to deduplicate a Kubernetes or docker-compose file, add them by hand after conversion. The output stays a plain expanded tree, which is what most tools expect anyway.