JSON vs XML vs YAML

How JSON, XML, and YAML actually differ in syntax, size, tooling, and safety — and which one to choose for APIs, configuration files, and documents.

7 min read

The same data, three ways

{
  "id": 42,
  "name": "Ada Lovelace",
  "roles": ["admin", "engineer"],
  "active": true
}
<user>
  <id>42</id>
  <name>Ada Lovelace</name>
  <roles>
    <role>admin</role>
    <role>engineer</role>
  </roles>
  <active>true</active>
</user>
id: 42
name: Ada Lovelace
roles:
  - admin
  - engineer
active: true

Three observations from those examples alone. XML is roughly twice the size, because every value is wrapped in an opening and closing tag. YAML is smallest, because it replaces punctuation with indentation. And XML has no native array — <roles> containing repeated <role> elements is a convention, not a type, which is why XML-to-JSON converters cannot reliably tell a one-element list from a single value.

Side by side

JSONXMLYAML
Best forAPIs, data interchangeDocuments, enterprise systemsHuman-edited config
SizeCompactVerbose (~2×)Most compact
CommentsNoYesYes
Native arraysYesNo (by convention)Yes
SchemaJSON SchemaXSD, DTD, RELAX NGJSON Schema (via conversion)
Type coercionNoneNoneAggressive — a real hazard
WhitespaceInsignificantInsignificantSignificant
Browser supportNativeNative (DOMParser)Library required
Grammar sizeOne pageLargeLarge (~80-page spec)
Parse safetySafeEntity-expansion risksArbitrary code in some loaders

Where JSON wins

Web APIs. JSON's types map straight onto the native types of nearly every language: object to dict/map, array to list, and the primitives to their obvious counterparts. Parsing is one call and no dependency in the browser.

Predictability. JSON has no implicit coercion. "no" is the string "no". "1.20" is the string "1.20". In YAML both may silently change type.

A grammar you can hold in your head. Six types and a page of rules. XML's specification runs to hundreds of pages once namespaces and entities are included; YAML's is around eighty.

Safety by construction. JSON cannot express a reference, an entity, or an executable construct. XML's entity expansion enables the "billion laughs" denial-of-service attack, and yaml.load in older PyYAML could instantiate arbitrary Python objects — which is why yaml.safe_load exists and should always be used.

Where JSON loses

No comments. For configuration this is a real limitation. Crockford removed them deliberately to stop implementers using them for parsing directives, and the omission is felt every time someone needs to explain a config value. Workarounds — a "_comment" key, or a relaxed superset such as JSONC — are all somewhat unsatisfying.

Verbosity in repetitive data. In an array of 50,000 objects, the same keys repeat 50,000 times. XML is worse; YAML anchors handle it better.

No date, binary, or decimal type. All three become strings by convention, and every consumer must know the convention.

No attribute/element distinction. XML separates metadata (attributes) from content (elements), which is genuinely useful for documents. JSON has one mechanism for both.

Mixed content. Text with inline markup — <p>See <a href="…">this</a> now.</p> — is what XML was designed for. Expressing it in JSON is awkward.

Choosing

Use JSON for REST and GraphQL APIs, browser storage, structured logs, machine-generated configuration, and anywhere a JavaScript client is involved.

Use XML for document markup, publishing and standards-driven formats (DocBook, TEI, SVG, RSS, Office formats), SOAP and enterprise integrations, and anywhere XSLT transformation or mature schema tooling is a requirement.

Use YAML for human-edited configuration — CI pipelines, Kubernetes manifests, Docker Compose, Ansible — where comments and low punctuation matter more than parsing strictness.

Many projects use two or three. Kubernetes manifests are YAML that is parsed into JSON. package.json is JSON while the CI config beside it is YAML. That is not inconsistency; it is picking the right tool for each boundary.

The YAML gotcha worth knowing

YAML 1.1 coerces unquoted scalars aggressively, and this bites in production:

country: NO        # → false, not "NO"        (the Norway problem)
version: 1.20      # → 1.2, not "1.20"
time: 22:30        # → 1350 (sexagesimal), not "22:30"
value: 08          # → error or 8, depending on the parser
enabled: on        # → true, not "on"

Quote anything whose exact string value matters. YAML 1.2 narrowed the boolean rules, but many parsers still default to 1.1 behaviour. JSON has no equivalent hazard, which is a genuine argument for machine-generated config.

Converting between them

Conversion is lossy in predictable directions, and knowing which way loses what avoids surprises.

XML → JSON loses the attribute/element distinction, and cannot reliably distinguish a single element from a one-element list. <roles><role>admin</role></roles> might convert to a string or to a one-element array; different converters disagree.

JSON → XML must invent element names for array items, since XML has no array type.

YAML → JSON loses comments, anchors, and multi-document separators. This is usually fine, because it is what parsers do internally anyway.

JSON → YAML is close to lossless — JSON is effectively a subset of YAML 1.2.

Related

Frequently asked questions

Is JSON better than XML?

For web APIs, usually yes — JSON is smaller, maps directly onto native data types in most languages, and needs no library in the browser. For document markup, where text and structure are interleaved and you need attributes, namespaces, or mature schema and transformation tooling, XML remains the better tool. "Better" depends entirely on whether you are describing data or marking up a document.

Should I use JSON or YAML for configuration?

YAML is generally more pleasant for human-edited configuration because it supports comments and needs less punctuation. JSON is safer for machine-generated configuration because its grammar is tiny and unambiguous, whereas YAML has significant whitespace and type-coercion rules that surprise people. Many projects use both: YAML for files people edit, JSON for files programs write.

Why does YAML turn "no" into false?

YAML 1.1 treats an unquoted y, yes, n, no, on, and off as booleans. This is the Norway problem: the country code NO becomes false. Version strings such as 1.20 become the number 1.2, and values like 08 can be read as octal. Quote any string whose meaning matters. JSON has no implicit type coercion, which is one of its genuine advantages.

Is JSON a subset of YAML?

Effectively yes since YAML 1.2, which was revised specifically to make valid JSON also valid YAML. Most YAML parsers will therefore accept a JSON document. The reverse is not true — YAML has many constructs, including comments, anchors, and multi-document files, with no JSON equivalent.

More in JSON Guide

← Back to JSON Guide