Migrating JSON Config to YAML: A Step-by-Step Guide

May 28, 20267 min read

Why Migrate from JSON to YAML?

JSON works fine for machine-to-machine communication, but configuration files written by humans benefit from YAML's readability. YAML supports comments, multi-line strings, and avoids the trailing-comma problem that plagues JSON editing.

Common motivations for migration:

  • Adding comments to explain configuration decisions
  • Reducing syntax noise — no braces or quotes needed for simple values
  • Using YAML anchors to deduplicate repeated configuration blocks
  • Better multi-line string handling for embedded scripts and templates

JSON vs. YAML: Structural Differences

FeatureJSONYAML
CommentsNot supported# line comments
Quotes on stringsRequiredOptional for simple values
Trailing commasSyntax errorNot applicable
Multi-line strings\n escapes onlyLiteral and folded block styles
Anchors/aliasesNot supported&anchor and *alias
Data typesString, number, bool, null, array, objectSame + date, timestamp, binary, sets
Root structureObject or arrayAny type (including scalar)

Step-by-Step Migration Process

Step 1: Audit Your JSON Files

Before converting anything, identify every JSON config file and its consumers. Ask:

  • Which applications read this file?
  • Do any tools write back to this file automatically?
  • Are there JSON schemas that validate these files?

Applications that both read and write the config may not support YAML output, which blocks full migration.

Step 2: Choose Your Conversion Method

Manual conversion: Open the JSON file, reformat to YAML syntax by hand. Feasible only for small files (under 50 lines).

Command-line tools: Use yq or jq for automated conversion:

# Using yq (recommended)
yq -y '.' config.json > config.yaml

# Using jq + python
jq '.' config.json | python3 -c "import sys, yaml, json; yaml.dump(json.load(sys.stdin), sys.stdout, default_flow_style=False)"

Online converters: Paste JSON, get YAML. Quick for one-off conversions but not suitable for sensitive configs.

Step 3: Convert the Syntax

Key transformations to apply:

{
  "database": {
    "host": "localhost",
    "port": 5432,
    "name": "myapp_production",
    "ssl": true
  },
  "features": ["auth", "logging", "metrics"]
}

Becomes:

database:
  host: localhost
  port: 5432
  name: myapp_production
  ssl: true

features:
  - auth
  - logging
  - metrics

Step 4: Add Comments and Documentation

Now that YAML supports comments, annotate non-obvious values:

database:
  host: localhost          # Override with DB_HOST env var in production
  port: 5432               # Default PostgreSQL port
  name: myapp_production
  ssl: true                # Required for RDS instances

Step 5: Update Application Code

Modify your application to read YAML instead of JSON:

// Node.js: Before
const config = require('./config.json')

// Node.js: After (using js-yaml)
const fs = require('fs')
const yaml = require('js-yaml')
const config = yaml.load(fs.readFileSync('./config.yaml', 'utf8'))
# Python: Before
import json
with open('config.json') as f:
    config = json.load(f)

# Python: After
import yaml
with open('config.yaml') as f:
    config = yaml.safe_load(f)

Always use safe_load in Python to avoid executing arbitrary YAML tags.

Step 6: Validate and Test

  • Run your test suite against the new YAML config
  • Verify that all values parsed correctly — YAML's type coercion can surprise you
  • Check that boolean values are correct (true/false, not "true"/"false")
  • Confirm numeric strings haven't been converted to numbers unexpectedly

Common YAML Parsing Surprises

Boolean Coercion

YAML treats several values as booleans:

YAML ValueParsed As
true, True, TRUE, yes, Yes, YES, on, On, ONtrue
false, False, FALSE, no, No, NO, off, Off, OFFfalse

If you have a country code NO (Norway), YAML parses it as false. Quote it: "NO".

Numeric Strings

version: 1.10    # Parsed as float 1.1, not string "1.10"
port: 08080      # Parsed as 8080 octal → 4160 decimal

Quote values that must remain strings: version: "1.10", port: "08080".

Indentation Errors

YAML is indentation-sensitive. Mixing tabs and spaces breaks parsing. Configure your editor to use spaces only.

Partial Migration Strategy

If some consumers can't read YAML, run both formats in parallel:

  1. Maintain YAML as the source of truth
  2. Generate JSON from YAML in your build step:
    yq -j '.' config.yaml > config.json
    
  3. Commit only the YAML file; git-ignore the generated JSON

This keeps your canonical config in readable YAML while supporting legacy consumers.

Key Takeaways

  • YAML adds comments, cleaner syntax, and anchors — worthwhile for human-authored configs
  • Audit all consumers before migrating; some tools may not support YAML output
  • Use yq for automated conversion or Python's yaml.dump for programmatic conversion
  • Watch for YAML's aggressive type coercion: quote strings that look like booleans or numbers
  • Always use safe_load (Python) or equivalent to avoid executing arbitrary YAML tags
  • For partial migrations, generate JSON from YAML in your build step

Try It Yourself

Convert JSON to YAML (and back) instantly with our free JSON-YAML Converter. Paste your data and switch formats in one click — no installation required.