JSON ↔ YAML Converter

Convert between JSON and YAML: anchors resolved, multi-document files handled, and output that round-trips.

YAML

1 document · top-level keys: name, tools, beta

Runs in your browser. Nothing you enter is sent anywhere.

How to use it

Pick JSON → YAML or YAML → JSON and paste into the source box. It converts as you type, in your browser; nothing you paste is uploaded.

  1. Choose 2 spaces or 4 spaces for the output’s indentation.
  2. Press Copy next to the result. The line under it counts the documents and lists the top-level keys (indexes, for an array).
  3. Press the other direction for a round trip: a valid result moves into the input and converts back.

Input that can’t be read shows one line instead, such as Line 2, column 8: reason.

Examples

A service config with JSON → YAML and 2 spaces:

{"service": "api", "version": "1.10", "region": "NO", "tls": "off", "replicas": 3, "ports": [8080, 8443]}
service: api
version: "1.10"
region: "NO"
tls: "off"
replicas: 3
ports:
  - 8080
  - 8443

Unquoted, 1.10 would read as the number 1.1, and a YAML 1.1 parser would read NO and off as false.

A Docker Compose file with an anchor and merge keys, with YAML → JSON:

x-defaults: &defaults
  restart: unless-stopped
  environment:
    LOG_LEVEL: info
services:
  web:
    <<: *defaults
    image: nginx:1.27
  worker:
    <<: *defaults
    image: app:2.3
    restart: "no"
{
  "x-defaults": {
    "restart": "unless-stopped",
    "environment": {
      "LOG_LEVEL": "info"
    }
  },
  "services": {
    "web": {
      "restart": "unless-stopped",
      "environment": {
        "LOG_LEVEL": "info"
      },
      "image": "nginx:1.27"
    },
    "worker": {
      "restart": "no",
      "environment": {
        "LOG_LEVEL": "info"
      },
      "image": "app:2.3"
    }
  }
}

Each <<: *defaults copies the anchored mapping in, and a key written beside it, like the worker’s restart, wins.

Two Kubernetes documents, with YAML → JSON:

kind: ConfigMap
metadata:
  name: app-config
---
kind: Secret
metadata:
  name: app-secret
[
  {
    "kind": "ConfigMap",
    "metadata": {
      "name": "app-config"
    }
  },
  {
    "kind": "Secret",
    "metadata": {
      "name": "app-secret"
    }
  }
]

The status line reads 2 YAML documents became a JSON array. 2 documents · top-level keys: kind, metadata.

An unquoted colon, with YAML → JSON:

name: release
title: Fix: login loop

The error is Line 2, column 8: Nested mappings are not allowed in compact mappings. A colon followed by a space starts a key, so the value needs quotes: title: "Fix: login loop".

Good to know

  • YAML input is read as YAML 1.2. Only true and false (and True, FALSE) are booleans, so yes, on and NO stay strings. Unquoted dates stay strings, and 0755 is decimal 755; octal is 0o755.
  • YAML 1.1 parsers differ. PyYAML reads NO as false (the “Norway problem”), an on: key as True and 0755 as 493. So JSON → YAML quotes any string a 1.1 parser would misread, such as "yes", "01234", "2026-10-14" and "~", and the output reads the same under both. A %YAML 1.1 directive at the top, then ---, applies the old rules, but a date such as 2026-10-15 stays as written, not midnight UTC.
  • Numbers become IEEE 754 doubles in both directions. 3.10 comes out as 3.1, and integers past 2^53 − 1 lose digits: 12345678901234567890 becomes 12345678901234567000. YAML’s .inf and .nan become null, since JSON can’t hold them. Quote versions and long IDs.
  • Anchors and merge keys are expanded, not rebuilt. Converting back to YAML gives plain copies. An alias inside the node it points to fails with An alias points back at itself, which JSON cannot represent.
  • Duplicate keys differ by direction. YAML 1.2 requires unique keys, so a repeat fails with Map keys must be unique. JSON keeps the last silently, as JSON.parse does: {"a":1,"a":2} becomes a: 2.
  • Keys keep the order they’re written in, integer-like ones such as "404" included, which a JavaScript object sorts first.
  • Custom tags are dropped. CloudFormation’s !Ref MyBucket becomes "MyBucket".
  • YAML 1.1’s collection and binary types are spelled out. !!set {web, api} becomes {"web": null, "api": null}, since YAML defines a set as a mapping of nulls. !!omap becomes an object in its order, and !!binary its base64 text on one line.
  • Indentation is read as pasted, so a block copied from a larger file converts without dedenting. Tabs can’t indent YAML: such a line fails with Tabs are not allowed as indentation.
  • JSON errors read the same in every browser. The reader follows RFC 8259 and stops at the first character that breaks it: {"a": 1,} gives Line 1, column 8: A trailing comma before "}" is not allowed in JSON. Input is limited to 100,000 characters, and JSON to 500 levels of nesting.

Questions

How do I convert JSON to YAML?

Paste it with JSON → YAML selected and copy the result. In JavaScript, the yaml package’s YAML.stringify(JSON.parse(text), { schema: 'yaml-1.1' }) quotes ambiguous strings the same way; in a shell, mikefarah’s yq does it with yq -p json -o yaml file.json.

How do I convert YAML to JSON on the command line?

Use yq -o json file.yaml, or Python: python3 -c 'import sys, json, yaml; print(json.dumps(yaml.safe_load(sys.stdin), indent=2))' < file.yaml. PyYAML follows YAML 1.1, so NO becomes false, and an unquoted date becomes a date that json.dumps can’t serialize.

How do I validate YAML?

Paste it with YAML → JSON selected: if it converts, it’s well-formed YAML 1.2; if not, you get the first error with its line and column. It checks syntax, indentation and duplicate keys, not a schema, so a misspelled Kubernetes field still converts.

Is JSON valid YAML?

Yes: YAML 1.2 made JSON an official subset, so YAML → JSON accepts JSON too, apart from duplicate keys. The reverse isn’t true: comments, anchors and multiple documents have no JSON form.