YAML ↔ JSON ↔ TOML ↔ .env Converter

Paste a config in any of five formats and read it back in any other — it converts as you type. The input format auto-detects, or pin it manually. YAML anchors, aliases, the "<<" merge key and multi-document streams are fully supported. Hand-written parsers, no dependencies, nothing leaves your browser.

detected: {{ fromFormat }}

Input {{ fromFormat }}

{{ num }}
Waiting for input… ✕ {{ result.error }} ✓ Valid {{ fromFormat }}
Output {{ fromFormat }} → {{ toFormat }}
Indent Key case
{{human(origSize)}} → {{human(outSize)}} · {{deltaLabel}} · {{outLineCount}} lines
{{ num }}

What changed in this conversion{{ result.notices.length }}

note {{ note }}

Round-trip checkparse the output back and compare

About this converter

All five formats describe the same thing — a tree of keys, values, lists and nested groups — so every conversion here goes through one plain data structure in the middle: the input is parsed into it, the output is written from it. That is why the direction does not matter and why adding a format does not change how the others behave.

Where it gets interesting is that the formats are not equally expressive, and a converter that hides that is lying to you. TOML has no null, so a null key is written out as a comment rather than dropped silently. .env has no lists or nested maps, so nested keys flatten to SECTION__KEY and lists serialize as comma-separated values or JSON. Every edge case produces a visible notice so you know what changed.

YAML anchors, aliases and merge keys are fully resolved, not just recognized and rejected: &name defines an anchor (on a scalar, a flow collection, or a following indented block), *name aliases it back in as a deep copy, and a mapping's <<: *name merge key splices in the anchored mapping's keys as defaults — an explicit key in the same mapping always wins over a merged one. Anchors are scoped to a single document, matching the YAML spec. Every alias/merge resolution is logged as a field-path notice below, since JSON (and the other targets) have no equivalent concept to show it as. A bounded expansion budget rejects a "billion laughs"-style alias chain instead of hanging the tab. Defining a brand-new anchor inside a flow collection ({v: &a 1}) is the one form left unsupported — real-world YAML almost always anchors block-style values instead.

Multi-document streams ("---"-separated, optionally ending in "...") parse to a JSON array, one entry per document — the same convention most YAML tooling uses. Converting that array back to YAML produces an ordinary block sequence, not another "---"-separated stream; there's no way to tell after the fact whether an array originated as a multi-document stream or a genuine YAML list, so the round trip is asymmetric on purpose rather than guessed at.

The round-trip check parses the output back into a value and diffs it against the original parse, field by field — a structural proof the conversion actually reproduced the same data, rather than trusting the notices above to have named every lossy edge.

Everything is evaluated locally in your browser. Configs often carry API keys, secrets, database URLs and token signing keys; this page has no analytics, no third-party scripts and nowhere to send them to — nothing you paste is uploaded, logged or stored.