JSON / YAML / TOML Converter
Paste JSON, YAML or TOML and get the other two back, with syntax errors pinned to the exact line and column. Runs entirely in your browser — nothing you paste is uploaded.
About this tool
The three formats look interchangeable and are not. JSON knows six kinds of value and nothing else. YAML adds comments, indentation as structure, and several ways to write the same string. TOML adds real integers, datetimes, and a rule that the top level must be a table. Converting between them therefore has genuinely lossy corners, and this tool names them instead of hiding them — a value that cannot survive the trip is reported, not dropped.
The most useful thing a converter can do is tell you where you went wrong. Config files fail for two reasons almost every time: a missing or extra comma in JSON, and indentation that does not line up in YAML. Both are invisible until something refuses to load, and both are solved instantly by a line number. So the parser here reports positions rather than just failing, and it refuses to guess: YAML anchors and tags are reported as unsupported rather than turned into strings that look like they worked.
All of it runs in the page. Configuration files carry credentials, internal hostnames and connection strings — exactly the content that should not be pasted into a server. Nothing here is uploaded, requested or logged, and you can verify that by disconnecting your network and using it anyway.
Why a YAML file with uneven indentation is rejected
Because the parser stops where the structure stops lining up, and returning only the part it understood would be worse than failing. Any leftover lines are reported with the line number where the mismatch begins.
YAML has no closing braces, so indentation is the only thing marking where a nested block ends. Get one level wrong and the file either fails to parse or — far worse — parses into a smaller structure than you wrote. The second failure is invisible: the conversion succeeds, the output is valid, and a whole section of your configuration is quietly missing.
So the parser checks that nothing is left over after the top-level node has been consumed. If a line remains that is neither blank nor a document marker, the file is rejected at exactly that line. You get a position to look at instead of a result that dropped half the input.
It is also why a tab in the indentation does not break the file. YAML forbids tabs as structure, but real files contain them, so the line scanner gives a tab the width of two spaces and the levels still sort correctly. Being lenient about one tab is cheap; being lenient about a missing level is not.
Why a string that looks like a number comes back quoted
On output, any value that would be re-read as a number or a keyword is wrapped in quotes, so text stays text. A quoted "123", or a yes written as a string, survives a round trip rather than turning into a number or a boolean.
YAML scalars are untyped until something decides otherwise. Without quoting, the text 123 written into a file is read back as the number 123, and a bare yes is read as the keyword yes by plenty of parsers. The serialiser avoids that by inspecting every string before it writes it and quoting anything ambiguous — the empty string, keywords such as true, false, null, yes, no, on and off, anything that parses as a number, and anything beginning with a character that carries meaning in YAML.
The same question has a different answer in each format. TOML strings are always double-quoted by the grammar, and JSON keys and strings are always quoted, so no decision is needed there. YAML is the only one of the three where whether a value needs quotes depends on what the value looks like.
The practical consequence: if the source had 01234 as an unquoted zip code, it was already the number 1234 before this tool saw it, and it is still a number afterwards. Quoting preserves text; it never invents quotes for something that was not text to begin with.
How TOML tables are rebuilt when the file is written out
A table that holds only sub-tables gets no header of its own, because the full path of each child already names that level. A table with no keys at all does get one, since otherwise it would disappear from the output entirely.
The emitter walks the data structure, writing scalar values under the current table header and then recursing into each sub-table under its own full path. If it wrote a header for every level, a file with tool.pytest.ini_options would gain an empty [tool] and [tool.pytest] in front of the real one, which reads as though those tables exist and are empty.
So an intermediate table is skipped when it carries no values of its own. A genuinely empty table is treated differently because it must be written or the round trip loses it. In the data the two look identical, so the rule keys on whether the table has entries, not on what it is called.
Arrays of tables keep the double-bracket form and repeat the header once per element. The plain table and the array-of-tables shapes are told apart by looking at the value: an array whose entries are all tables becomes an array of tables, and any other array stays a value.
Error positions are computed here, not copied from the error text
All three parsers are written here, and so are the positions. Runtime error messages often carry no position, especially on short input, and an error without a position is barely an error: you only know something somewhere is wrong.
Writing the parser is not for show; it keeps the verdict local. JSON still goes through the built-in JSON.parse, but only as a syntax checker and a value extractor, with the position tracked here. Blending the two produces reports that point somewhere while the syntax at that spot is perfectly legal.
The value domain is a controlled set: null, boolean, number, string, array and object, with nothing else entering the structure. That makes convertibility a definite question instead of something to try and then guess about.
Separating position from verdict has a useful side effect: the same text keeps pointing at the same line and column across all three formats, so a reader can fix what the message names, convert again, and not be led to a different character simply because the format changed.
Frequently asked questions
Why can my empty value not be written as TOML?
TOML has no null. There is no spelling for "this key exists and its value is nothing", so a JSON null or a YAML empty value has nowhere to go. Rather than silently deleting the key — which would change the meaning of your data — the converter reports the path and leaves the other formats intact.
Will the converter reformat my file beyond the target syntax?
It reads the file into a data structure and writes that structure out again, so the target output is normalised: keys keep their order, indentation is standardised, and quoted strings are re-quoted only where the target format needs it. Comments do not survive — neither JSON nor TOML has anywhere to keep a YAML comment. If you need comments preserved, convert by hand.
Why do TOML datetimes come out as strings?
TOML has four datetime shapes, including "local" ones that carry no timezone at all. JavaScript has one date type and it always has a timezone, so mapping them into it would invent information that was never in the file. Keeping the literal text means the value survives a round trip unchanged, and the output is still valid TOML.
Can it read YAML anchors and aliases?
No, and it says so rather than guessing. An anchor like &base with an alias *base is a real feature of the YAML spec, but expanding them correctly means reimplementing the whole spec, and getting it half right produces output that looks plausible and is wrong. Files that use them are reported with the line number so you know exactly what to rewrite.
Does my data get sent anywhere?
No. Parsing and formatting both happen in the page with no network access of any kind. There is no analytics call, no error reporting, and no server to send to — the tool keeps working with your connection turned off.
Related tools
Format SQL and translate it between MySQL, PostgreSQL and SQLite. Every change is listed, and anything that cannot be translated safely is flagged instead of guessed — all in your browser.
Test a regular expression against your own text, see every match and capture group highlighted, get each piece of the pattern explained, and check what JavaScript, PCRE and RE2 actually support. Everything runs in your browser.
Generate names, emails, usernames, UUIDs, IP and MAC addresses, Luhn-valid card numbers and more — seeded so the same seed always yields the same rows, entirely in your browser.
Paste two name lists from Excel, Sheets or CSV and see what matches, what is unique to each side, and which entries are duplicates or near-misses. Nothing leaves your browser.