JSON to YAML Converter
Last updated: 2026-09-17
Paste JSON and get formatted YAML output. Key order is preserved from the original JSON. The converter handles nested objects, arrays, Unicode strings, and special characters that require quoting in YAML. No data leaves your browser.
What this tool does
Converts a JSON document into YAML 1.2 output with 2-space indentation. The conversion is lossless: every JSON type (object, array, string, number, boolean, null) maps to an equivalent YAML type. Key order is preserved. The output uses no anchors, aliases, or tags, making it portable across YAML parsers.
The converter runs entirely in your browser. Pasted input is parsed with the standard JSON parser, passed through js-yaml configured with indent: 2, lineWidth: 120, noRefs: true, and sortKeys: false, then rendered in the output panel. Nothing is sent to a server, stored, or logged, which makes the tool suitable for secrets, credentials, and internal configuration that must not leave your machine.
Example
Input:
{"server":{"host":"localhost","port":8080},"features":["auth","logging","cache"],"debug":false}Output:
server:
host: localhost
port: 8080
features:
- auth
- logging
- cache
debug: falseJSON vs YAML: key differences
| Feature | JSON | YAML |
|---|---|---|
| Quotes on keys | Required (double) | Optional |
| Comments | Not allowed (RFC 8259) | Allowed (# only) |
| Multi-document | Not supported | Supported via --- |
| Anchors/aliases | Not supported | Supported (& and *) |
| Booleans | true / false only | YAML 1.1: yes/no/on/off; YAML 1.2: true/false |
| Null | null | null, ~, or empty |
| Line breaks | \n escape | Literal or folded block scalars |
| Trailing commas | Not allowed | Not allowed |
YAML block styles
YAML has two families of scalar presentation: plain (unquoted) and quoted (single or double), plus two block scalar indicators for multi-line content: literal (|) and folded (>). The converter picks a presentation per value based on what the string contains.
- Plain scalars. Simple values like
localhost,8080, andauthare written without quotes. A string gets plain presentation only when it contains no colon followed by a space, no leading or trailing spaces, no hash, no indicator characters, and does not resemble a boolean, number, null, or date. - Double-quoted strings. When a string contains a colon followed by space, a leading hash, indicator characters, or trailing whitespace, the converter wraps it in double quotes. The converter prefers double quotes for any value needing quoting, because double-quoted style can express every escape sequence and the tool targets YAML 1.2.
- Literal block scalars. Strings that contain newline characters are written with the
|indicator, which preserves each line break exactly. A value containing two lines separated by a newline becomes a literal block where each source line is indented under the key. This is the default multi-line presentation the converter produces. - Folded block scalars. The
>indicator folds internal newlines into spaces, treating paragraphs as single long lines. The converter never emits folded scalars; js-yaml selects literal style for any string containing line breaks, so folded output does not appear here.
Collections have two presentations as well. Block style uses indentation for mappings and a dash-prefixed list for sequences. Flow style uses braces {} and brackets [] with commas, resembling JSON. The converter emits block style for every non-empty mapping and sequence. Empty objects and empty arrays are the only flow-style output, written as {} and [] respectively.
The lineWidth: 120 option governs where flow-style content and long plain scalars wrap. With the limit set to 120 characters, a long flow collection breaks onto multiple lines only after exceeding 120 columns. Block-style collections are not affected by line width because they are already structured by indentation.
Single-quoted strings are not emitted by the converter, but worth knowing: single quotes differ from double quotes in YAML because they cannot represent all escape sequences and escape a lone single quote by doubling it. The converter consistently uses double quotes when quoting is required, so you will not see single-quoted output even for strings that contain an apostrophe.
When to use YAML instead of JSON
YAML is the preferred format for configuration files in ecosystems like Kubernetes, GitHub Actions, OpenAPI, and docker-compose. Its indentation-based structure and comment support make it more readable than JSON for hand-edited files. JSON is better for data interchange between systems: it is simpler, has a smaller parsing surface, and every JSON parser handles it identically.
For large payloads, prefer JSON. YAML parsers are slower and more memory-hungry than JSON parsers because the grammar is larger and indentation must be tracked. A multi-megabyte YAML document can take noticeably longer to load than the equivalent JSON, and the readability gains of indentation vanish at that scale anyway. Streaming parsers exist for both formats, but JSON streaming is more mature and widely deployed in production pipelines.
Converting Kubernetes manifests
A Kubernetes manifest stored as JSON converts cleanly to YAML because the data is nested mappings and sequences with string and number values. Given this JSON input:
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "api-server",
"namespace": "production",
"labels": {"app": "api", "tier": "backend"}
},
"spec": {
"replicas": 3,
"selector": {"matchLabels": {"app": "api"}},
"template": {
"metadata": {"labels": {"app": "api", "tier": "backend"}},
"spec": {
"containers": [
{
"name": "api",
"image": "registry.example.com/api:1.4.2",
"ports": [{"containerPort": 8080}],
"env": [{"name": "LOG_LEVEL", "value": "info"}]
}
]
}
}
}
}The converter produces indented YAML with the same key order, 2-space indentation, and single-item sequences rendered as block lists. The matchLabels mapping, the containers sequence, and the nested template.spec all stay in block style. Strings such as apps/v1 remain unquoted because the slash is not a special character in YAML plain scalars. The numeric value 3 for replicas stays a number, and 8080 stays an integer rather than becoming a string.
Because the manifest mixes single-element arrays (one container, one port, one environment variable) with multi-key mappings, the block-style output spreads each value onto its own line. Sequence items begin with a dash and a space, and their nested keys align under the first letter of the item. This alignment matters when you diff manifests across revisions: identical key order means an unchanged field stays on the same line, so pull request reviewers see only the lines that actually changed.
Converting GitHub Actions workflows
GitHub Actions workflows are large YAML documents that teams sometimes generate from JSON templates. Converting the JSON form back to YAML keeps the key order that GitHub expects. Given this JSON input:
{
"name": "CI",
"on": {
"push": {"branches": ["main"]},
"pull_request": null
},
"permissions": {"contents": "read"},
"jobs": {
"build": {
"runs-on": "ubuntu-latest",
"steps": [
{"uses": "actions/checkout@v4"},
{"uses": "actions/setup-node@v4", "with": {"node-version": "20", "cache": "npm"}},
{"run": "npm ci"},
{"run": "npm test"}
]
}
}
}The converter emits a workflow document where the on key, the push mapping, and each entry in the steps sequence are indented consistently. The null value for pull_request becomes null in the YAML output, matching YAML 1.2. Step entries that mix uses, with, and run keys render as block mappings inside the sequence. String values like ubuntu-latest and actions/checkout@v4 stay plain because hyphens, dots, and at-signs do not trigger quoting in YAML plain scalars.
Note: the on key is a YAML 1.1 boolean in some parsers. The converter writes it unquoted because js-yaml targets YAML 1.2, where on is not a boolean. If your downstream tooling parses with YAML 1.1 rules, quote the key manually as "on":.
Workflows benefit from conversion because teams frequently maintain the canonical definition in JSON (often generated by a policy tool or templating engine) and render it to YAML for the repository. Round-tripping through this converter keeps the structure intact: job names, step ordering, matrix dimensions, and environment variable lists all preserve their original sequence. When a step contains only a uses key, it renders as a one-line mapping; when a step adds a with block, the block indents two spaces beneath the step entry.
Gotchas
The Norway problem. In YAML 1.1, the two-letter country code NO is interpreted as boolean false. The same applies to yes, no, on, off, Y, and N. This converter uses YAML 1.2 conventions (only true/false), but downstream parsers may use YAML 1.1. Quote such values to force them to remain strings.
Date-like strings. A value like 2024-01-15 matches the YAML date pattern and may be parsed as a date object by some YAML loaders. Wrap it in quotes if it should stay a string.
Numbers as strings. Values like 0123 may be interpreted as octal in YAML 1.1. Quote them to preserve the string representation.
Indentation. YAML uses indentation for structure, not braces. A single wrong space can change the document structure. This converter produces consistent 2-space indentation, but if you edit the output by hand, be careful. A common failure is outdented sequence items: a dash that sits at the same column as the parent mapping key detaches the items from that key and attaches them to the enclosing context.
Common mistakes when converting JSON to YAML
- Tabs for indentation. YAML forbids tabs for indentation. The converter uses spaces, but if you copy JSON that was pretty-printed with tabs and edit the YAML output by hand, replace every tab with spaces before saving.
- Missing space after the colon. In JSON,
"key":"value"is valid. In YAML,key:valueis a single scalar, not a mapping. YAML requires a space after the colon:key: value. The converter always emits the space. - Unquoted booleans from YAML 1.1. The values
yes,no,on,off,Y, andNare booleans under YAML 1.1. This converter writes them unquoted because it targets YAML 1.2, but if a downstream loader uses YAML 1.1, quote them. - Trailing whitespace in multi-line strings. Literal block scalars chomp trailing newlines by default. A string ending with a line break loses that trailing break unless a keep indicator (
|+) is present. The converter uses the default clip behavior, so trailing newlines are dropped. - Assuming flow and block output are identical. Flow style
{a: 1}and block style witha: 1on its own line are semantically the same, but tooling that greps for indentation-dependent patterns may treat them differently. - Forgetting that key order is not semantically meaningful. YAML mappings are unordered by specification, even though this converter preserves the order from your JSON. Do not rely on ordering for correctness, only for readability.
- Editing the lineWidth output by hand. Long lines wrapped at 120 characters by the converter may be re-wrapped or unwrapped if you edit them. Re-run the converter after structural changes instead of hand-wrapping.
- Treating null and an empty string as equivalent. JSON
nullbecomes YAMLnull, not an empty scalar. An empty JSON string""becomes''in the output. These are distinct values downstream.
Do it in code
Node.js (js-yaml):
const yaml = require('js-yaml');
const json = '{"name":"test","value":42}';
const output = yaml.dump(JSON.parse(json), { indent: 2, noRefs: true, sortKeys: false });
console.log(output);To match this converter exactly, also pass lineWidth: 120. The dump options used here mirror the tool: indent controls the number of spaces per nesting level, noRefs prevents anchor and alias output for repeated object references, and sortKeys: false keeps the original insertion order. The converter never sets flowLevel, so all nested collections render in block style rather than collapsing into inline braces at a given depth.
Python (PyYAML):
import json, yaml
data = json.loads('{"name":"test","value":42}')
print(yaml.dump(data, sort_keys=False, allow_unicode=True))CLI (jq + yq):
echo '{"name":"test","value":42}' | jq '.' | yq -y '.'Note: yq here refers to the Python-based yq (pip install yq), which wraps jq. The Go-based yq (mikefarah/yq) uses a different syntax.
Round-tripping JSON through YAML
Converting a JSON document to YAML and then parsing it back should, in principle, reproduce the original data unchanged. Both formats describe the same core structures—mappings, sequences, and scalars—so a faithful round trip preserves types, values, and nesting. In practice, several pitfalls can alter the result before you notice.
Date-like strings are the most frequent surprise. A value such as 2024-01-15 is a plain string in JSON, but many YAML loaders promote it to a native date object, which then serializes differently when written back to disk. Large integers can lose precision when a loader coerces them into floating-point representations, dropping trailing digits or shifting exponent boundaries. Duplicate keys, which the JSON parser already collapses to the final occurrence, vanish entirely after the round trip, hiding earlier values from anyone reviewing the output afterward.
To guarantee fidelity, quote date-like strings before conversion, keep integers within safe numeric ranges, and eliminate duplicate keys at the source rather than relying on the converter to surface them. When absolute equivalence matters, diff the round-tripped output against the original payload programmatically.
Edge cases handled
- Nested objects and arrays at any depth are converted to the corresponding YAML mapping and sequence structures.
- Empty objects
{}become{}in YAML; empty arrays[]become[]. - Strings containing colons, leading spaces, hash symbols, or other YAML special characters are automatically quoted.
- Unicode characters (including emoji, CJK, accented characters) are preserved without escaping.
- Circular references are detected and reported as an error instead of producing YAML anchors.
- Duplicate keys in a JSON object are silently collapsed to the last value by the JavaScript parser before conversion; YAML output reflects only that final value per key.
- Very deeply nested structures (hundreds of levels) still convert correctly, though the resulting indentation may exceed what some editors highlight or what some linters consider readable.
- Binary,
undefined,NaN, andInfinityvalues are not representable in standard JSON, so they never reach the converter; such tokens cause the JSON parser to fail before any YAML is emitted. - Tab characters embedded inside string values are preserved as literal tabs within double-quoted scalars, since the converter does not convert tabs to spaces inside quoted strings.