Skip to content
jsonforge.app
Back to blog
Guide11 min read

JSON vs XML vs YAML: Choosing the Right Data Format

JSON, XML, and YAML can all describe the exact same data — a user record, a config file, an API payload — but they optimize for different things. Picking the wrong one for a given job usually shows up later, as unreadable config diffs or a parser that can't express what you need. This guide compares the three head-to-head on syntax, size, speed, and feature set, and gives a concrete rule of thumb for each.

The same data, three ways

Here's one small object represented in all three formats. Comparing them side by side is the fastest way to see what each format actually trades off.

JSON — explicit brackets and quotes, no ambiguity about structure.
json
{
  "user": {
    "name": "Ada Lovelace",
    "roles": ["admin", "editor"],
    "active": true
  }
}
YAML — the same data, using indentation instead of brackets.
yaml
user:
  name: Ada Lovelace
  roles:
    - admin
    - editor
  active: true
XML — the same data, using opening/closing tags and attributes.
xml
<user active="true">
  <name>Ada Lovelace</name>
  <roles>
    <role>admin</role>
    <role>editor</role>
  </roles>
</user>

Same three fields, three very different amounts of punctuation. That difference is the whole story: JSON is the most machine-friendly, YAML is the most human-friendly to write by hand, and XML is the most expressive when the document itself needs structure beyond simple key/value data.

Where JSON wins

JSON is the default for a reason: it maps directly onto the data structures every mainstream language already has (objects/dicts and arrays/lists), so parsing it round-trips into native types with zero ambiguity. It has no comments, no multiple ways to write the same value, and no whitespace sensitivity — which sounds limiting but is exactly what makes it fast to parse and safe to generate programmatically.

Use JSON for anything machine-to-machine: REST and GraphQL API payloads, data passed between services, anything stored in a document database (MongoDB, PostgreSQL's JSONB), and any config that's primarily read and written by code rather than edited by hand.

Where YAML wins

YAML is a strict superset of JSON's data model with a much friendlier syntax for humans: no closing brackets to count, comments with #, and indentation instead of punctuation. That's exactly what you want for files a person edits directly and re-reads in a diff — CI pipelines (GitHub Actions, GitLab CI), Kubernetes manifests, and application config.

The trade-off is that YAML's flexibility is also its biggest footgun: indentation errors silently produce a different structure instead of a parse error, and unquoted values like `no`, `yes`, `on`, and dates can be auto-converted to booleans or timestamps you didn't intend (the infamous 'Norway problem', where the country code NO becomes the boolean false). Quote your strings when there's any ambiguity.

Where XML wins

XML looks like legacy overhead next to JSON, but it does things neither JSON nor YAML can: attributes alongside element content, mixed content (text and elements interleaved, like HTML), namespaces for combining vocabularies from different sources, and mature schema validation (XSD) plus transformation (XSLT) tooling that predates JSON by a decade.

That's why XML persists in document-centric domains — SOAP APIs, SVG, DOCX/XLSX (which are ZIP files full of XML), and enterprise systems (banking, healthcare, government) with existing XSD-validated pipelines nobody is rewriting. If your data is genuinely document-shaped (think 'a paragraph with a bolded span in the middle') rather than record-shaped, XML is often still the better fit.

Size and parsing speed

For the same record-shaped data, YAML is typically the smallest on disk, JSON lands within a few percent of it, and XML runs roughly 30–40% larger than JSON once you count closing tags and either attributes or wrapper elements. A 1 KB JSON payload is usually around a 950-byte YAML file and a 1.3–1.4 KB XML document. Those gaps matter for files on disk, payloads embedded in bundles, and anything stored uncompressed; over HTTP they matter much less.

The reason is compression: gzip and brotli — which nearly every production API and CDN enables — squash repeated punctuation and indentation to almost nothing, and all three formats compress well. After brotli, the minified-JSON and pretty-YAML versions of the same data usually land within a few percent of each other. Parsing tells a similar story: JSON.parse is a native, heavily optimized code path in every browser and in Node, YAML needs a library and a far heavier grammar, and XML sits in between. None of it is measurable for config parsed once at startup; on a hot path, JSON's cheap parser is a real advantage.

Comments, multi-document files, and other sharp edges

Comments: YAML has them (#), XML has them (<!-- -->), JSON does not — a deliberate choice. If documents could differ only by a comment, implementations that strip or keep comments would disagree about equality, which breaks signatures, hashes, and cache keys.

Multi-document files: YAML separates documents with ---, so one file holds a stream of records; XML permits exactly one root element; JSON defines a single value per document, with JSON Lines — one minified document per line — as the ecosystem convention for streams. YAML also has anchors and aliases (&anchor / *alias) for reuse, which JSON has no equivalent for.

Each format has a characteristic sharp edge. YAML's indentation sensitivity and implicit type coercion (the Norway problem) mean a file can parse successfully into a different structure than you intended. XML's entity expansion is an attack surface (the XXE vulnerability class) in misconfigured parsers, and namespaces add verbosity JSON never has. JSON's own edge is milder than both — no comments, no date type, integer precision capped at 2^53 — which is precisely why it's the safest of the three to accept from untrusted sources.

Converting between formats

Since all three describe the same object/array/string/number/boolean/null data model (XML's attributes and mixed content are the one thing that doesn't map cleanly), converting between JSON, YAML, and XML is usually mechanical for anything record-shaped. JsonForge's JSON to YAML, YAML to JSON, JSON to XML, and XML to JSON tools handle the conversion in the browser, which is useful when you're migrating a config file's format or need to hand a YAML-only teammate a JSON export.

XML is the awkward direction: attributes versus child elements is a distinction JSON doesn't have, so every converter adopts a convention — attributes get an @ prefix, or land in a fixed sub-object — and a document round-tripped through it comes back a different shape. JSON ⇄ YAML conversion, by contrast, is essentially lossless in both directions.

FAQ

Is YAML just JSON with different syntax?
Almost — YAML 1.2 is a superset of JSON, meaning any valid JSON document is also valid YAML. But YAML adds features JSON doesn't have (comments, anchors/references, multi-document files) and its own parsing quirks (implicit type conversion), so the reverse isn't true: not all YAML is valid JSON.
Why do Kubernetes and CI tools use YAML instead of JSON?
Because those files are hand-written and hand-reviewed constantly. YAML's lack of brackets and support for comments make it far more pleasant to read and diff in a pull request than the equivalent JSON, even though JSON would parse identically.
Why does XML still exist if JSON is simpler?
XML supports things JSON structurally cannot: attributes on elements, mixed text/element content, namespaces, and schema validation via XSD. Formats built on top of XML — SVG, DOCX, XLSX, SOAP — rely on exactly those features, which is why XML hasn't disappeared even though JSON won for typical REST APIs.
What is the YAML 'Norway problem'?
In YAML, unquoted `NO` (Norway's country code) is parsed as the boolean `false`, because YAML auto-converts unquoted `no`/`yes`/`on`/`off` to booleans. It's a well-known gotcha — always quote country codes, version strings, and anything that looks like a boolean or number but is meant as a literal string.
Why doesn't JSON support comments?
Because comments would break the guarantee that equal data has exactly one serialized form. JSON is an interchange format generated and compared by machines — with comments, two parsers can disagree about whether two documents are identical, which breaks signing, hashing, and caching. JSONC and JSON5 exist for hand-edited config, but they're supersets, not JSON.

Try these tools

Related articles