YAML to JSON Converter

Paste a manifest, a compose file or a pipeline config. Anchors and merge keys are resolved, dates stay the strings you wrote, and the JSON comes back pretty, minified or one object per line. Nothing leaves your machine.

Need to reshape the result rather than read it? Open the app

Why a config file ends up as JSON

Almost nobody converts YAML to JSON because they prefer reading JSON. They do it because a tool on the other side only speaks JSON. Four jobs cover most of it:

  • Validating a manifest against a schema. JSON Schema tooling is mature and everywhere. YAML schema tooling is thinner.
  • Querying with jq. Every image tag in a compose file is a one-line expression once the file is JSON.
  • Diffing two releases. YAML lets the same structure be written several ways, so textual diffs are noisy. Pretty JSON normalises the formatting and leaves the real changes.
  • Feeding an API or a template. Request bodies, Terraform variable files and most template engines want JSON.

Worked example: a compose file that leans on anchors

Shared blocks are house style in compose files and CI configs, because repeating six lines of logging settings per service is how they drift apart. Here is one, with an anchor named defaults and two services pulling it in:

x-defaults: &defaults
  restart: unless-stopped
  logging:
    driver: json-file
  environment:
    TZ: Etc/UTC

services:
  api:
    <<: *defaults
    image: registry.example.com/billing-api:2.4.1
    ports:
      - "8080:8080"
  worker:
    <<: *defaults
    image: registry.example.com/billing-worker:2.4.1
    replicas: 3

And the JSON, exactly as the converter writes it on the default settings:

{
  "x-defaults": {
    "restart": "unless-stopped",
    "logging": {
      "driver": "json-file"
    },
    "environment": {
      "TZ": "Etc/UTC"
    }
  },
  "services": {
    "api": {
      "restart": "unless-stopped",
      "logging": {
        "driver": "json-file"
      },
      "environment": {
        "TZ": "Etc/UTC"
      },
      "image": "registry.example.com/billing-api:2.4.1",
      "ports": [
        "8080:8080"
      ]
    },
    "worker": {
      "restart": "unless-stopped",
      "logging": {
        "driver": "json-file"
      },
      "environment": {
        "TZ": "Etc/UTC"
      },
      "image": "registry.example.com/billing-worker:2.4.1",
      "replicas": 3
    }
  }
}

The merge key is gone and both services carry the full settings. That is the point. JSON has no anchors, so a converter that left << alone hands you an object with a key spelled << and the defaults hanging off it, which no downstream tool understands. Plenty do exactly that, because the merge tag is an optional extra in the YAML 1.2 core schema.

Override order follows the merge specification. Had worker declared its own restart: always, that value would win and the merged one would be dropped.

Dates come out as dates, not timestamps

This is the difference I would check first in any YAML converter. YAML 1.1 defined a timestamp tag, so created: 2024-11-03 loaded as a date object, and writing that object back out gives whatever the writer feels like: an ISO timestamp in a timezone nobody specified, an epoch number, occasionally [object Object]. The reader here uses the YAML 1.2 core schema, which has no timestamp tag, so the value stays "2024-11-03", character for character.

The core schema settles the other YAML 1.1 traps in your favour too. An unquoted no stays the string "no" rather than becoming false, and so do yes, on and off. A value like 12:30 stays a string instead of being read as sexagesimal. Only lowercase true and false are booleans.

Pretty, minified, or one object per line

  • Pretty is two-space indentation, for reading a manifest, committing the JSON, or diffing two of them.
  • Minified is one line, for a request body or an environment variable. A two-key file becomes {"a":1,"b":"two"}.
  • JSON Lines only makes sense when the YAML is a list. A sequence of two maps becomes two compact lines and the download is named .jsonl.
  • Try an example loads a Kubernetes ConfigMap carrying a date, a quoted region code and a nested list.

Gotchas worth knowing

  • Several documents become an array. A file with --- separators gives one entry per document, plus a note saying how many there were.
  • Duplicate keys are refused, not silently merged. Two name keys in one mapping produce Line 3: duplicated mapping key. Some parsers keep the last and say nothing, which is how a config change lands in staging and is ignored in production.
  • Unquoted leading zeros are numbers. zip: 01730 loads as 1730, because the core schema reads it as an ordinary integer. Quoting it in the source fixes it, and 1.10 is the same trap.
  • Infinity and not-a-number become null. .inf and .nan have no JSON equivalent, so they land as null.
  • Tabs are a syntax error. YAML forbids them in indentation and the message names the line.
  • Files up to 100 MB, no row cap, no daily quota. Alias references are capped at ten thousand per file, so a runaway config errors instead of wedging the tab.

Frequently Asked Questions

Does it resolve anchors, aliases and merge keys?

Yes, all three. An alias is replaced by whatever its anchor held, and a merge key writes the anchored block's keys into the map that pulled it in. Keys a map declares for itself win over merged ones.

Is my YAML uploaded anywhere?

No. The parser is JavaScript running in your tab, with no upload endpoint behind this page. That matters here, because config files hold hostnames, bucket names and internal service topology. Nothing is kept between visits.

What happens to dates and timestamps?

They stay strings. A line reading created: 2024-11-03 becomes "2024-11-03", character for character. YAML 1.1 had a timestamp tag that turned those into date objects, and every way of writing one back out changes what the file said.

My file has several documents separated by three dashes. What do I get?

One JSON array with one entry per document, plus a note saying how many there were. A single document converts unwrapped, to the value itself. A bundle holding a Service, a Deployment and an Ingress becomes three objects.

Why did my version number 1.10 come out as 1.1?

Because unquoted, 1.10 is a number in YAML, and 1.10 and 1.1 are the same number. Quote it in the source and it stays the string "1.10". Leading zeros are the same trap: 01730 loads as 1730.

It refused my file and named a line. What does that mean?

The file is not valid YAML and the number is the line to open. Duplicate keys report as "Line 3: duplicated mapping key", which matters because a duplicate silently loses data in some parsers. Tabs in indentation report the same way.

Convert your YAML to JSON

No sign-up, no upload, no row cap. Anchors resolved, dates left alone, output copied or downloaded in one click.

Back to the converter