Skip to main content

YAML vs JSON: Syntax Differences, When to Choose Each, and How to Convert

A developer's guide to the concrete syntax differences between YAML and JSON — where they bite you, when to pick each, and how to convert cleanly in both directions.

Published By Li Lei
#yaml #json #config #devops #developer-tools

YAML vs JSON: Syntax Differences, When to Choose Each, and How to Convert

YAML and JSON both describe the same fundamental data shapes — key-value maps, ordered lists, scalars — but the choices each format made about whitespace, quoting, and type inference create sharp edges that catch developers mid-debug. I've spent hours tracking down a bug that turned out to be YAML silently coercing a bare NO into the boolean false, which then failed a string comparison downstream. That kind of silent conversion doesn't happen in JSON. But JSON can't hold a comment, which means a configuration file without inline documentation is a future maintenance problem. Both tradeoffs are real. Choosing well depends on knowing exactly where the edges are.

The Core Syntax Side-by-Side

The same data looks like this in each format. Take a minimal service configuration with a name, port, TLS flag, and a list of allowed origins:

JSON:

{
  "name": "api-gateway",
  "port": 8080,
  "tls": true,
  "allowedOrigins": [
    "https://app.example.com",
    "https://admin.example.com"
  ]
}

YAML:

name: api-gateway
port: 8080
tls: true
allowedOrigins:
  - https://app.example.com
  - https://admin.example.com

The YAML version is 30–40% shorter by character count for typical config files (a consistent finding across large Kubernetes manifest comparisons), and it accepts comments — add # production gateway above the name line and no parser complains. The JSON version is stricter: every key must be quoted, every value separated by a comma, every structure enclosed in braces or brackets. That strictness is exactly what makes JSON reliable for machine-to-machine data exchange.

Four Syntax Differences That Actually Bite

1. YAML has implicit typing; JSON does not

In JSON, type is explicit. "8080" is a string. 8080 is a number. true is a boolean. You decide by writing the value with or without quotes.

In YAML, the parser infers type from bare values. This produces a list of surprises:

| YAML bare value | Parsed as | |-----------------|------------------| | true | boolean true | | yes | boolean true | | on | boolean true | | no | boolean false | | off | boolean false | | null | null | | ~ | null | | 1e3 | float 1000.0 | | 0x1F | integer 31 | | 2026-07-01 | date object |

If a country code abbreviation like NO appears unquoted in a YAML config, it becomes false. A Git branch name like on/feature in a value would coerce on to true before the slash. The fix is simple — quote the value — but the bug shows up at runtime, not at parse time.

JSON never has this problem. "NO" is always the string NO. There is no implicit coercion.

2. YAML supports multi-line strings natively; JSON does not

YAML has two block scalar styles:

# Literal block — newlines preserved
description: |
  This service handles
  authentication requests.
  Each line is kept.

# Folded block — newlines become spaces
summary: >
  This is a long sentence
  that will be folded
  into a single line.

JSON must encode newlines explicitly:

{
  "description": "This service handles\nauthentication requests.\nEach line is kept.",
  "summary": "This is a long sentence that will be folded into a single line."
}

For config files with embedded scripts, SQL queries, or error message templates, YAML's block syntax is substantially more readable. In JSON, those same values are escaped single-line strings that need a text editor with JSON-aware formatting to read.

3. YAML anchors and aliases; JSON requires repetition

YAML lets you define a value once and reference it multiple times:

defaults: &defaults
  timeout: 30
  retries: 3

production:
  <<: *defaults
  host: prod.example.com

staging:
  <<: *defaults
  host: staging.example.com

Both production and staging inherit timeout and retries without repetition. JSON has no equivalent. You copy the values or build the merging logic into your application or a preprocessing step (like Jsonnet or JSON Schema $ref).

4. Trailing commas and comments

JSON forbids both. A trailing comma after the last array element or object property is a syntax error. No comment syntax exists at all.

YAML allows neither trailing commas (it uses indentation) nor has a comment syntax problem — # comments work anywhere.

This matters most during code review: JSON configs can't explain why a flag is set a certain way inline. You need an adjacent documentation file or a pull-request description. YAML config authors write the reasoning next to the value, where it won't drift.

When to Choose YAML

Pick YAML when:

  • Humans are the primary authors. CI/CD pipelines (GitHub Actions, GitLab CI), infrastructure manifests (Kubernetes, Helm charts, Ansible playbooks), and application configs (Docker Compose, Rails) all favor YAML because the edit-review-commit cycle involves humans reading line-by-line.
  • You need comments. Any config that requires explanation — environment-specific flags, non-obvious timeouts, feature toggle conditions — belongs in a format that supports inline documentation.
  • Multi-line strings appear often. Embedded shell scripts, SQL, or templated messages are far less painful to maintain in YAML's block style.

When to Choose JSON

Pick JSON when:

  • Machines are the primary consumers. REST API payloads, WebSocket messages, database documents (MongoDB, Elasticsearch), and browser localStorage all speak JSON. Every language's standard library includes a JSON parser; YAML is usually a third-party dependency.
  • Strict typing matters. When "true" and true must never be confused, JSON's explicit quoting removes a whole class of coercion bugs from your system.
  • You need maximum portability. JSON parses identically in JavaScript, Python, Go, Java, Rust, and every other language with a mainstream JSON library. YAML 1.1 vs 1.2 parser differences (the yes/on boolean behavior is YAML 1.1 only, not 1.2) mean the same file can parse differently across tools.
  • Package ecosystem tooling expects it. package.json, tsconfig.json, composer.json, .prettierrc — these are JSON because the tools that read them ship a JSON parser and nothing else.

Converting Between the Two

The conversion is straightforward when you know the direction. To go from YAML to JSON, use the YAML to JSON converter — paste your YAML, get minified or pretty-printed JSON back instantly. The converter handles anchors (expands them to their full form), infers types faithfully, and flags invalid YAML before you copy-paste into a downstream system that gives unhelpful parse errors.

The reverse direction — JSON to YAML — is handled by the JSON to YAML converter. Paste a JSON object, get clean indented YAML. Anchors are not re-introduced automatically (that would require the tool to guess your intent), but the output is valid, readable, and directly editable.

A real conversion example. Input YAML from a GitHub Actions workflow fragment:

env:
  NODE_ENV: production
  PORT: "3000"
  DEBUG: false
steps:
  - name: Install
    run: npm ci
  - name: Build
    run: npm run build

Converted output JSON:

{
  "env": {
    "NODE_ENV": "production",
    "PORT": "3000",
    "DEBUG": false
  },
  "steps": [
    { "name": "Install", "run": "npm ci" },
    { "name": "Build", "run": "npm run build" }
  ]
}

Notice that PORT: "3000" preserved its string type in the output because it was quoted in the YAML source. DEBUG: false correctly converts to the boolean false. This is the conversion working as expected — the challenge is only when you receive YAML that has unquoted port numbers or version strings (version: 3.8 converts to the float 3.8, not the string "3.8").

Practical Checklist Before Committing

Before committing a YAML config:

  • Quote any value that looks like a number, boolean, or date but should stay a string.
  • Run the file through a formatter like the YAML Formatter to normalize indentation before review.
  • If a value contains a colon (common in URLs), either quote the whole value or write it in block style.

Before committing JSON:

  • Validate with a formatter to catch trailing commas and missing quotes — those are the two most common JSON syntax errors.
  • Move multi-line content into an external file or a template system rather than embedding escaped newlines.

Both formats are mature, well-supported, and appropriate in the right context. Knowing the syntax differences means you spend the time designing your system, not chasing a parser error that an implicit boolean coercion introduced three files upstream.


Made by Toolora · Updated 2026-07-01