jsonpost
YAMLConfigDevOps

YAML vs JSON for Configuration: A Developer's Guide

Compare YAML and JSON for config files — comments, anchors, multiline strings, the Norway problem, and when to convert between the two for your tooling.

JSONPost··5 min read
YAML vs JSON for Config

If you write configuration for a living, you have met both YAML and JSON, often in the same afternoon. They model the same data — maps, lists, scalars — but the ergonomics differ enough that picking the wrong one creates real pain. This guide walks through the practical trade-offs, the gotchas that bite teams, and how to convert between the two when your tooling demands it.

The same data, two shapes

Both formats describe key-value structures. Here is a small service config in JSON:

{
  "service": "billing",
  "replicas": 3,
  "env": {
    "LOG_LEVEL": "info",
    "TIMEOUT": 30
  },
  "regions": ["us-east-1", "eu-west-1"]
}

And the equivalent YAML:

service: billing
replicas: 3
env:
  LOG_LEVEL: info
  TIMEOUT: 30
regions:
  - us-east-1
  - eu-west-1

The YAML version is shorter, has no closing braces to balance, and drops most quotes. For files that humans edit by hand all day, that readability adds up.

Where YAML pulls ahead

Comments

JSON has no comments. None. That single limitation is why so many config ecosystems abandoned it. YAML supports comments with #:

replicas: 3 # bumped for Black Friday traffic
# TODO: move secrets to the vault before launch
env:
  LOG_LEVEL: debug

In JSON you are reduced to fake "comment" keys like "_comment": "...", which clutter the data and confuse parsers.

Multiline strings

Embedding a script or a certificate in JSON means escaping every newline as \n on one enormous line. YAML offers block scalars that keep text readable. The | style preserves newlines; the > style folds them into spaces:

startup_script: |
  #!/bin/sh
  echo "starting"
  exec ./server --config /etc/app.yaml
description: >
  This long sentence will be folded
  into a single line when parsed.

The same startup_script in JSON is one cramped string:

{
  "startup_script": "#!/bin/sh\necho \"starting\"\nexec ./server --config /etc/app.yaml"
}

Anchors and aliases

YAML can define a value once and reuse it with anchors (&) and aliases (*), optionally merging maps with <<. This removes copy-paste from repetitive configs:

defaults: &defaults
  retries: 3
  timeout: 30

billing:
  <<: *defaults
  endpoint: /api/billing

shipping:
  <<: *defaults
  endpoint: /api/shipping

JSON has no equivalent — you repeat the block every time.

Where JSON pulls ahead

JSON is not the underdog everywhere. It wins on:

  • Speed and ubiquity. Every language ships a fast, battle-tested JSON parser. YAML parsers are slower and vary in feature support.
  • Determinism. JSON has one obvious way to write most values. YAML has many, and "clever" YAML is hard to review.
  • Wire format. APIs speak JSON. You would never send YAML over HTTP as a response body.
  • No surprising type coercion — which brings us to the famous gotchas.

The gotchas that bite teams

The Norway problem

YAML 1.1 interprets a long list of bare words as booleans. The country code for Norway is NO, and unquoted it becomes false:

countries:
  - NO   # becomes false!
  - SE
  - DK
enabled: yes   # becomes true
shipping: off  # becomes false

Parsed, that list silently contains a boolean where you expected a string. The fix is to quote anything that could be misread:

countries:
  - "NO"
  - "SE"
  - "DK"
enabled: true

Numbers that are not numbers

Version strings and zip codes love to lose data. A value like 1.20 becomes the number 1.2, and a leading-zero zip like 01234 may be parsed as octal or stripped to 1234. Quote them:

version: "1.20"
zip: "01234"
git_sha: "0e9f8a7"

Indentation and tabs

YAML uses indentation for structure, and tabs are forbidden for indentation. A single stray tab or a misaligned space throws a parse error that points at the wrong line. Configure your editor to insert spaces and show whitespace. JSON, with its explicit braces, sidesteps this entirely.

Trailing-colon and flow ambiguity

A map value that starts with a special character can confuse the parser. When in doubt, quote the scalar. The general rule: YAML's flexibility is exactly what makes it error-prone, so be conservative.

Converting between them for your tooling

Most infrastructure tools accept YAML because humans author it, but they parse it into the same data model as JSON. That means you can convert freely, and you often need to.

Kubernetes manifests are usually YAML, but kubectl and the API server accept JSON too. When you generate manifests programmatically, emitting JSON and converting is cleaner:

# pipe a generated JSON manifest through conversion before applying
cat deployment.json | your-json-to-yaml > deployment.yaml
kubectl apply -f deployment.yaml

GitHub Actions workflows are YAML. If a script produces job configuration as JSON, convert it before committing:

{
  "name": "CI",
  "on": ["push"],
  "jobs": {
    "test": {
      "runs-on": "ubuntu-latest",
      "steps": [{ "run": "npm test" }]
    }
  }
}

That maps directly to a .github/workflows/ci.yml file:

name: CI
on:
  - push
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: npm test

Docker Compose is YAML, but if your platform exports service definitions as JSON, the same round-trip applies.

When you need to go either direction, paste your config into the YAML to JSON converter to feed APIs and validators, or the JSON to YAML converter to produce human-friendly manifests. Both preserve structure so you can move between the readable and the machine-friendly form without retyping anything. If you want to confirm the output is well-formed before committing, run it through the JSON validator.

A quick decision guide

  • Editing by hand, want comments and reuse, targeting DevOps tools? YAML.
  • Sending data over the wire, parsing in code, want speed and zero ambiguity? JSON.
  • Generating config in a program but deploying to a YAML tool? Author in JSON, then convert.

Whatever you choose, quote your ambiguous scalars, use spaces not tabs, and keep your anchors readable.

Conclusion

YAML and JSON are two views of the same data: one optimized for humans, one for machines. Knowing the gotchas — the Norway problem, silent number coercion, and indentation traps — lets you use YAML's readability without getting burned. And because they share a data model, converting between them is lossless and quick.

Ready to convert? Drop your config into the YAML to JSON or JSON to YAML tool and ship with confidence. Explore more developer utilities on the JSONPost blog.

Keep reading