Skip to content
CornerTools

YAML to JSON Converter

Convert YAML to JSON and back, with errors by line and the YAML pitfalls flagged.

1
1
Characters: 0

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, on and off as booleans, 0777 as octal and 12:30 as 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

Each value written plain, after a key, as the tool reads it
YAMLYAML 1.2YAML 1.1
yes"yes"true
no"no"false
NO"NO"false
on"on"true
off"off"false
y"y"true
0777777511
0o1715"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

Reviewed

Frequently asked questions

A YAML 1.1 reader takes the country code 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.
Not in JSON, which has no comments; a note says when some were dropped. Going from JSON back to YAML cannot bring them back.

See also