Skip to content

All tools (41)

JSON 6
Time & Date 4
Encoding & Decoding 4
Generators 3
Text & Data 4
Logs & Debugging 1
Config & Infra 3
Security & Hashing 4
Color & Design 5
Numbers & Bits 3
Web & Markup 4

Nothing leaves the cave.

Nothing you paste ever leaves your device. There is no server to send it to.

How you can check →
DevToolsCave

    This tool runs entirely in your browser. Nothing you paste is uploaded.

    How you can check →

    YAML to JSON

    Config & Infra

    Convert YAML to JSON in your browser. Anchors, merge keys, tags and multiple documents all map to a defined JSON shape or refuse loudly by name — never silently.

    JSON
    The JSON appears here.

    Worked example: a docker-compose file with anchors and merges

    YAML

    # Shared defaults for every service in this stack.
    # Edit here once rather than in each service block.
    x-common: &common
      restart: no
      logging:
        driver: json-file
    
    version: "3.9"
    
    services:
      api:
        <<: *common
        image: registry.example.com/cave-api:2026.09.12
        ports:
          - "8080:8080"
    
      worker:
        <<: *common
        image: registry.example.com/cave-worker:2026.09.12
    

    JSON

    {
      "x-common": {
        "restart": "no",
        "logging": {
          "driver": "json-file"
        }
      },
      "version": "3.9",
      "services": {
        "api": {
          "image": "registry.example.com/cave-api:2026.09.12",
          "ports": [
            "8080:8080"
          ],
          "restart": "no",
          "logging": {
            "driver": "json-file"
          }
        },
        "worker": {
          "image": "registry.example.com/cave-worker:2026.09.12",
          "restart": "no",
          "logging": {
            "driver": "json-file"
          }
        }
      }
    }

    Verified — converting back gives the same 17 values in the same order. 2 aliases expanded, 2 merges applied, 2 comments dropped, 3 values read differently under YAML 1.1.

    What a YAML reader decides that JSON never has to

    JSON's grammar makes a value's type explicit at the syntax level: a string is always in quotes, a number is always bare digits, true/false/null are reserved words. YAML instead resolves an unquoted scalar's type from its spelling, and two real, widely deployed specs disagree about that resolution — YAML 1.1 (SnakeYAML, PyYAML, go-yaml v2: Spring Boot, Ansible, Kubernetes tooling) and YAML 1.2 core (js-yaml 4, the yaml npm package, ruamel). Converting YAML to JSON means picking one of those readings and writing it down as an explicit JSON type — which is exactly the step every converter that "just" wraps JSON.stringify(yamlLib.load(text)) gets partly wrong, because it silently inherits whichever spec its underlying library happens to implement.

    The two specs and who runs which

    Six real YAML readers, by spec
    ReaderSpecUsed by
    YAML 1.2 core1.2js-yaml 4, yaml 2, ruamel.yaml, YamlDotNet, libfyaml, yq (Go)
    PyYAML1.1PyYAML, Ansible, Home Assistant, pre-commit, mkdocs
    SnakeYAML1.1SnakeYAML, Spring Boot, Jenkins
    go-yaml v21.1Kubernetes tooling, Helm, kubectl, kustomize
    go-yaml v31.2-ishCompose v2, many Go CLIs
    Psych1.1Ruby (stdlib), Rails, GitLab CI

    This tool resolves YAML 1.2 core by default — the modern reading, and what a visitor's mental model of "YAML" usually is in 2026 — but the Readers tab always shows the YAML 1.1 reading too, unconditionally, because the honest fact about a bare no in your file is that some real deployment target reads it as false whether or not you asked to see that.

    Anchors, and why the JSON is bigger

    An anchor (&common) marks a node for reuse; an alias (*common) copies it. JSON has no notion of a reference, so every alias becomes a real, independent copy of the anchored value in the output — which is why a compact YAML file with three services sharing one anchored block can produce noticeably larger JSON. This is not a flaw in the conversion; it is what "JSON cannot express sharing" actually means once you write it down. The receipt counts how many aliases were expanded so the size difference is explained rather than mysterious.

    Merge-key precedence, in one sentence

    <<: *base merges base's entries underneath the mapping's own keys — a key already present in the mapping always wins over the merged-in value, never the other way around — and <<: [*a, *b] merges left to right, so an earlier alias in the list wins over a later one where they overlap. This is the detail most docs state backwards, and it is why the docker-compose worked example above merges x-common's defaults into both services without either service having to repeat them.

    Multiple documents

    A YAML file with one or more --- separators becomes a JSON array by default — one element per document, in source order — with "first document only" and NDJSON available as one-click alternatives in the Reading options. This tool refuses to guess: some competing libraries throw outright on multi-document input rather than offering a shape for it at all.

    Tags, and what JSON cannot hold

    A core tag like !!str 123 or !!int "12" forces a specific reading regardless of spelling, and maps directly. !!binary has no JSON byte type, so the base64 text is kept as written, noted as such. An unrecognised local tag such as !Env is refused by name and line, with an option to keep the value and drop the tag instead of guessing what it meant. CloudFormation's own short-form tags (!Ref, !GetAtt, !Sub and the rest) are the one local-tag family this tool does map automatically, once a template is detected — see the section below.

    CloudFormation short forms

    A CloudFormation template written with short-form intrinsic tags — !Ref Bucket instead of {"Ref": "Bucket"} — is exactly the kind of file the two most common libraries handle worst: js-yaml throws outright on the unrecognised tag, and yaml 2 silently drops the tag and keeps only the bare value, which quietly turns a reference into an unrelated string. This tool auto-detects a CloudFormation template (from AWSTemplateFormatVersion, or a Resources key together with a CFN-named tag actually present) and maps every intrinsic — !Ref, !Sub, !GetAtt, !Join, !If, !Select, !Split, !FindInMap, !Base64, !Cidr, !ImportValue, !GetAZs, !Transform, !Condition, !And, !Or, !Not, !Equals — to its Fn:: long form. Detection always shows its evidence as a dismissable badge; it never engages silently.

    Doing this from the terminal

    • yq -o=json input.yaml — mikefarah's yq is a 1.2-family reader, so a 1.1-only value (a bare no, a leading-zero octal) resolves differently from what Spring Boot or Ansible would actually construct from the same file.
    • python -c 'import yaml, json; print(json.dumps(yaml.safe_load(open("input.yaml"))))' — PyYAML's safe_load is a 1.1 reader (no y/n booleans, a stricter float pattern), so its answer differs from every 1.2 tool on the same traps, and merge keys resolve differently depending on the PyYAML version.
    • node -e "console.log(JSON.stringify(require('js-yaml').load(require('fs').readFileSync('input.yaml','utf8'))))" — js-yaml's load rewrites a bare date into a full ISO timestamp with a time component you never wrote, and throws outright on an unrecognised tag rather than mapping or refusing it by name.

    Common use cases

    • Turning a docker-compose file with anchors and merges into JSON for a config-diffing tool
    • Converting a CloudFormation template's short-form tags into their explicit Fn:: shape
    • Checking exactly which values a Kubernetes or Ansible reader would resolve differently
    • Auditing a multi-document Kubernetes List before splitting it into separate manifests
    • Confirming how many comments a YAML file would lose before committing to a JSON pipeline

    Frequently asked questions

    Why did no become a string and not false?
    Because this tool resolves YAML 1.2 core by default, and 1.2 core's boolean set is only true/false — no is plain text under 1.2. YAML 1.1 (SnakeYAML, PyYAML, go-yaml v2 — the parsers Spring Boot, Ansible and Kubernetes tooling actually use) reads a bare no as false, and the Readers tab shows that difference unconditionally, whichever spec you pick, because the honest fact about this file is that some real deployment target reads it differently.
    My file has !Ref — why did other tools fail?
    !Ref is a CloudFormation short-form tag, not core YAML — js-yaml 4 throws on an unrecognised tag entirely, and yaml 2 silently drops the tag and keeps only the bare value, which quietly turns {"Ref":"BucketName"} into just the string "BucketName". This tool detects a CloudFormation template (from AWSTemplateFormatVersion or a Resources key together with a CFN-named tag) and maps every intrinsic tag to its Fn:: long form instead, shown as a dismissable badge with the evidence for the detection.
    Where are my comments?
    JSON has no syntax for a comment, so they cannot travel across — but they are not silently discarded either. The Notes tab counts exactly how many were dropped and from which lines, each one a clickable jump back to the source, which is more than the comment report most competing tools give you (most give none at all).
    Why is the JSON in a different order from other tools?
    It isn't — theirs is. Most YAML-to-JSON converters run through a plain JavaScript object in the middle, and `JSON.stringify` on a plain object moves integer-like keys ("2", "10") ahead of alphabetic ones regardless of how they were written. This tool's tree keeps insertion order for every key kind, so a document with keys "10" then "2" prints in that order, matching the file you pasted.
    Multiple documents?
    A YAML file with --- separators becomes a JSON array by default — one array element per document — with "first document only" and NDJSON one click away in the Reading options. NDJSON is the one case an array-of-JSON-values already maps onto multiple documents naturally, which is why it is offered as its own option rather than requiring you to split the array yourself afterwards.
    Is anything uploaded?
    No. The parser, the resolver and the verification all run in this tab's own JavaScript. Nothing is sent to a server, logged, or stored — open the Network tab before you paste to confirm it for yourself.