YAML to JSON Converter
Convert YAML to JSON and back, with errors by line and the YAML pitfalls flagged.
Converts YAML to JSON and JSON to YAML: Kubernetes manifests, docker-compose and GitHub Actions files, OpenAPI documents. Errors name their line and column, and values that YAML 1.1 and YAML 1.2 read differently, such as no, on and 0777, are flagged rather than silently typed.
Numbers keep the digits they were written with in both directions, and the YAML written here quotes every string that any YAML reader could take for something else. It runs in your browser: nothing you paste or open is sent anywhere.
Options
- YAML version — 1.2, the current version and the default, or 1.1, which reads
yes,no,onandoffas booleans,0777as octal and12:30as a base-60 number. Many tools still read YAML as 1.1, PyYAML among them. - Indent — for the JSON, 2 spaces, 4 or a tab; for the YAML, 2 or 4 spaces (YAML does not allow tabs for indentation).
- Quote all strings — off by default, when only strings a reader could misread are quoted.
- Multi-line strings as | blocks — writes a string with line breaks as a literal block, line for line, rather than on one line with
\n.
Several documents separated by --- become one JSON array, with a note. Merge keys (<<) are applied, the map's own keys winning over merged ones. Anchors and aliases are expanded, up to 100,000 values in all, so a “billion laughs” file stops with an error instead of filling the memory. A key written twice keeps its last value, with a warning. Tags such as CloudFormation's !Ref are dropped with a note, their values kept; comments are dropped too, as JSON has none.
A YAML number is written to JSON as written when that is a JSON number (1.10 stays 1.10), otherwise as its value (0x1F becomes 31). .inf and .nan have no JSON form and are an error naming their line. YAML 1.1 timestamps stay as the text written. Switching between the two directions carries the output into the input.
Examples
A Kubernetes file with two documents
- Input YAML
apiVersion: v1 kind: Service metadata: name: web # the public entry point spec: ports: - port: 80 targetPort: 8080 --- apiVersion: v1 kind: ConfigMap metadata: name: web-config data: LOG_LEVEL: info RETRIES: "3"- JSON output, default options
[ { "apiVersion": "v1", "kind": "Service", "metadata": { "name": "web" }, "spec": { "ports": [ { "port": 80, "targetPort": 8080 } ] } }, { "apiVersion": "v1", "kind": "ConfigMap", "metadata": { "name": "web-config" }, "data": { "LOG_LEVEL": "info", "RETRIES": "3" } } ]
The two documents become an array, and the comment is dropped, each with a note. RETRIES stays a string because it is quoted.
A docker-compose file with a merge key
- Input YAML
x-defaults: &defaults restart: always logging: driver: json-file services: web: <<: *defaults image: nginx:1.27 worker: <<: *defaults restart: on-failure image: app:2.4- JSON output
{ "x-defaults": { "restart": "always", "logging": { "driver": "json-file" } }, "services": { "web": { "restart": "always", "logging": { "driver": "json-file" }, "image": "nginx:1.27" }, "worker": { "logging": { "driver": "json-file" }, "restart": "on-failure", "image": "app:2.4" } } }
Each service takes the shared settings; the worker's own restart wins over the merged one.
A GitHub Actions workflow read as YAML 1.1
- Input YAML, YAML version 1.1
name: CI on: push: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - run: npm test- JSON output
{ "name": "CI", "true": { "push": { "branches": [ "main" ] } }, "jobs": { "test": { "runs-on": "ubuntu-latest", "steps": [ { "run": "npm test" } ] } } }
Under YAML 1.1, the key on is the boolean true, so the JSON key is "true", and the tool says so. Read as 1.2 it stays "on".
JSON to YAML that every reader agrees on
- Input JSON, JSON → YAML, default options
{ "country": "NO", "version": "1.10", "ratio": 1.10, "start": "08:30", "script": "set -e\nnpm ci\nnpm test\n" }- YAML output
country: "NO" version: "1.10" ratio: 1.10 start: "08:30" script: | set -e npm ci npm test
NO, 1.10 and 08:30 are quoted, since some reader would take each for a boolean or a number; the number 1.10 keeps its zero, and the script is a literal block.
Where YAML 1.1 and 1.2 disagree
| YAML | YAML 1.2 | YAML 1.1 |
|---|---|---|
yes | "yes" | true |
no | "no" | false |
NO | "NO" | false |
on | "on" | true |
off | "off" | false |
y | "y" | true |
0777 | 777 | 511 |
0o17 | 15 | "0o17" |
1_000 | "1_000" | 1000 |
12:30 | "12:30" | 750 |
Standards
YAML 1.2 is read with its core schema; YAML 1.1 with the types of the 1.1 type repository, including the merge key, which YAML 1.2 dropped but most tools still apply.
Sources
- YAML Ain't Markup Language (YAML) version 1.2.2 — YAML Language Development Team
- Boolean Language-Independent Type for YAML 1.1 — YAML Language Development Team
- Merge Key Language-Independent Type for YAML 1.1 — YAML Language Development Team
- RFC 8259: The JSON Data Interchange Format — IETF
Reviewed
Frequently asked questions
NO for the boolean false, so a list of countries loses Norway. YAML 1.2 reads it as text, but many tools still read 1.1. The tool flags such values in YAML you paste, and quotes them in YAML it writes.See also
- JSON Formatter & Minifier — to check and format the JSON.
- JSON Schema Validator — to validate the converted JSON against a schema.