Convert JSON to YAML
Every converter writes country: NO without quotes. Half the YAML readers in the world then read it as false. This one quotes it, and reads its own output back to prove it.
Runs in your browser0 bytes uploadedEvery converter writes country: NO without quotes. Half the YAML readers in the world then read it as false. This one quotes it, and reads its own output back to prove it.
Runs in your browser0 bytes uploadedValues an older YAML reader would turn into a boolean, a number or a date get quotes. Costs two characters and removes the question for every parser. For data with nothing risky in it, this output is character-for-character identical to the other setting.
Each - sits under its key. What Prettier and most hand-written files do.
Purely cosmetic: a long string is never folded where folding would change it — one with double spaces gets quotes instead.
Nothing at the counter yet. Paste JSON, drop a .json file anywhere on the panel to the left, or press Use an example.
The structure part of this job is genuinely trivial. Objects become mappings, arrays become sequences, and the nesting carries over one level at a time. Any competent library does that correctly on the first attempt, which is why so many converters exist and why they all look alike. The part nobody shows you is the other half: for every single string in your file, the writer has to decide whether to put quotes around it. That decision is not cosmetic. Get it wrong and the value your reader receives is a different type from the value you sent.
The reason is that YAML resolves bare scalars by pattern. A word that looks like a number becomes a number, a word that looks like a boolean becomes a boolean, and the patterns are not the same in the two versions of the specification that are both in active use. So the writer is really answering a question about the future: who is going to open this?Most converters answer it without asking, by using their library's defaults, and those defaults target the newer rules.
We generated a corpus of 30,803 strings — every combination up to three characters over the alphabet that makes scalars ambiguous, plus the known troublesome shapes — wrote each one out with the library's default settings, and read it back with an older parser. 728 of them came back as something other than the string we started with: 715 turned into numbers, 12 into booleans, and one into a timestamp.
Those 728 are not academic. The famous member of the set is the Norwegian country code, spelled the same way as one of the six words the older rules accept for false. But the corpus turned up shapes that no hand-written list of dangerous words would ever have contained. A maintenance window written 12:30 arrives as the integer 750, because the old rules read colon-separated digits as base sixty. A readable thousands separator, 1_000, arrives as 1000. A bit pattern, 0b1010, arrives as 10. A release date arrives as a timestamp object rather than the eight characters you typed. And the two-character string e5 arrives as a number whose value is null, which is a sentence worth reading twice.
That is why this tool never consults a word list. For each distinct string in your input it asks the parser directly — write this value bare, read it back, is it still the same string? — once per unique string and cached, at roughly seventeen microseconds each. The answer cannot drift out of date relative to the library, because the answer is the library.
Having found the problem, the tempting fix is to write everything with the older rules in mind, since quoting more is never wrong. That is most of the answer and it is not all of it. Running the corpus the other way round found ten strings that survive an old reader and break in a new one, and all ten have the same shape: the octal notation 0o17, which the newer specification added and the older one has no concept of. Written bare it is a string to one reader and the number 15 to the other.
Closing both directions leaves nothing behind. Checked as values and again as keys, against both parsers, that is 123,160 comparisons with zero disagreements. The output carries no version marker and uses no version-specific syntax — quoting a scalar makes it text everywhere, so a file written this way is read the same by whatever opens it.
Feed this tool the string 007 and it comes out with quotes around it, in every setting, and arrives intact. That is worth dwelling on, because the identical five characters are beyond rescue in the opposite direction. A zip code, an order reference or a part number that was already written bare in somebody's YAML has already been read as a number by the time any tool sees it, and no setting anywhere recovers the missing digit. Going this way you still have the type information — JSON told us it was a string — and the only thing needed is to not throw it away. Converting YAML to JSON is the same pair of formats and the opposite situation: there the ambiguity is already baked into the source, and the best a tool can do is count the damage and name it.
YAML lets a block be written once and pointed at afterwards, and turning that on here folds any structure that is identical all the way down into a single copy with a label. It is off by default for two reasons. Blocks of fewer than two fields get skipped, since a label costs more characters than it saves. More importantly, an alias says these two thingsare the same thing, not merely that they currently match — and JSON cannot express that at all, so nothing in your input told us it was true. Take the result back through a converter in the other direction and every reference expands into a full copy again. The data survives the round trip; the text does not.
A converter that starts with the browser's built-in JSON reader has already lost the end of any integer longer than about seventeen digits before it looks at a single character. 12345678901234567890 arrives as 12345678901234567000, and that is what gets written into your YAML with no mention of it anywhere. This tool reads your input with the same scanner that powers our JSON formatter, which keeps the digit sequence exactly as typed. The same scanner is what makes it possible to notice a repeated key instead of silently keeping the last one, and to tell 1.0 apart from 1 — YAML writes both as 1, which is the same value spelled differently, and the receipt says so rather than letting you find out.
Analysis is only as trustworthy as the assumptions underneath it, and the analysis above is ours. So after writing the document the tool parses it again, once with each set of rules, and compares the result against the JSON you handed over. The parser is a separate piece of code from the writer, so a mistake in one cannot hide behind a belief shared with the other. When they disagree the receipt says so plainly instead of presenting the file as finished.
There is one limit and it is stated rather than hidden. Parsing cost grows faster than document size — 26 ms at 12 KB, 418 ms at 129 KB, 6.1 seconds at 539 KB — so above 64 KB the read-back is skipped and the panel says the output was not checked. An unverified result must never be dressed up as a verified one. The per-value analysis still runs at every size, because it is linear.
Four things account for nearly every file that fails here, and none of them produce a useful message from a browser's built-in reader. Single quotes instead of double ones, usually from a Python or JavaScript source. Comments, which JSON has never allowed. A comma after the final item, which most languages tolerate and this format does not. And Python's True, False and None, which arrive whenever somebody printed a dictionary instead of serializing it. Each gets its own explanation with a line, a column and the offending line quoted with a caret underneath. If the file turns out to be several JSON objects one per line, that is JSON Lines rather than JSON, and the message says how to wrap it.
There is no upload step here because there is nowhere to upload to: the site is static files, this page is identical for everyone who opens it, and the conversion is a function call on the text in the box. That matters more for this format than for most, because of what people are usually converting. JSON destined to become YAML is nearly always configuration — a deployment description, a service definition, a pipeline — and configuration carries hostnames, account identifiers, registry credentials and the shape of an internal network. Pasting that into a page that posts it somewhere is a disclosure with a friendly interface. You can check this one yourself in about ten seconds: open the network panel, hand the tool a file, and watch nothing happen. If you would rather see the method written out, the guide on checking that a tool is local covers it properly.
Because the two-letter country code for Norway is spelled exactly like one of the six words YAML 1.1 accepts as false, along with no, off, n, and their true counterparts. Write it bare and a 1.1 parser hands back a boolean. YAML 1.2 removed that rule in 2009, but the parsers people actually run did not all follow: PyYAML, Ruby's Psych and anything reaching Kubernetes through go-yaml v2 still read the old way. A converter that writes the value bare is betting that nobody downstream is one of those, and it is making that bet on your behalf without telling you. Quoting costs two characters and removes the question for every reader in both versions. If you would rather have the bare form, the setting is there and the risky values are still counted and named, so it stays a decision rather than an accident.
It asks the parser rather than checking a list. For every distinct string in your JSON it writes the value out bare, reads it back with a YAML 1.1 reader and again with a 1.2 reader, and compares the result with what you started with. Anything that comes back as a different type or a different value is reported with its path. This matters because the obvious word list is wrong in both directions. Running it over a generated corpus of 30,803 strings found 728 that a 1.1 reader changes, and the surprises were not the famous ones: 12:30 becomes the number 750, 1_000 becomes 1000, 0b1010 becomes 10, 2001-12-14 becomes a timestamp, and e5 becomes a number whose value is null. None of those would have been on a hand-written list of suspicious words.
Yes, and that is the point. Quoting a scalar makes it a string in every version of YAML, so the compatible output is read identically by old and new parsers. There is no version directive written into the file and no 1.1-only syntax used. One detail runs the other way and is handled too: YAML 1.2 added 0o octal notation, which 1.1 does not have, so a string like 0o17 written bare is a string to an old reader and the number 15 to a new one. That is quoted as well. Over the same corpus, checked as both values and keys against both readers, the compatible output has zero disagreements in 123,160 comparisons.
The digits are kept exactly as you wrote them. This is worth calling out because it is the one thing a converter built on JSON.parse cannot do: a number longer than about seventeen digits has already lost its tail before the converter ever sees it, so 12345678901234567890 arrives as 12345678901234567000 and gets written out that way with no warning anywhere. This tool reads your JSON with its own scanner and keeps the digit sequence, which is also how it can keep duplicate keys visible and tell 1.0 apart from 1. Numbers that YAML does write differently, such as 1e3 becoming 1000, are listed on the receipt rather than changed silently.
It can, and it is off by default. Turn it on and any structure that is identical all the way down is written once with an &anchor and referenced afterwards with an *alias, which is what a hand-written docker-compose.yml usually looks like. Two caveats keep it honest. Blocks with fewer than two fields are left alone, because an anchor on a one-field object makes the file longer rather than shorter. And an alias is a YAML idea with no JSON equivalent, so converting the result back the other way expands every reference into a full copy again — the file will not round-trip to the same text, only to the same data.
Yes. After writing the YAML it reads the whole document back with both a 1.1 and a 1.2 parser and compares the result against the JSON you supplied. The parser is a separate code path from the writer, so a mistake in the quoting logic cannot hide behind an assumption shared with the check. When the two disagree the receipt says so instead of presenting the output as fine. There is a limit: parsing is superlinear in document size, measured at 26 ms for 12 kB and 6.1 seconds for 539 kB, so above 64 kB the check is skipped rather than freezing your tab to prove something the per-value analysis already established. When that happens the receipt says the output was not read back, because an unchecked result must not look like a checked one.