← Back to Blog

JSON vs YAML: Complete Format Comparison

Detailed comparison of JSON and YAML. Learn when to use each format, conversion methods, and best practices for configuration files.

Emily Watson9 min readcomparison
E

Emily Watson

Technical Writer & Web Developer

Emily is a web developer and technical writer with 6 years of experience covering JavaScript ecosystems, developer tooling, and data formats. She specialises in making complex technical concepts approachable for developers at all levels, with a particular focus on JSON fundamentals, formatting best practices, and the tools developers reach for every day.

JSON BasicsJavaScriptWeb APIsDeveloper ToolingTechnical Writing
9 min read

JSON vs YAML Overview

Both are data serialization formats with different strengths.

Quick Comparison

| Feature | JSON | YAML |

|---------|------|------|

| Syntax | Lightweight | More concise |

| Readability | Good | Excellent |

| Comments | No | Yes |

| Parsing | Faster | Slower |

| File Size | Larger | Smaller |

Syntax Comparison

JSON

{

"name": "John",

"age": 30,

"active": true,

"tags": ["user", "admin"]

}

YAML

name: John

age: 30

active: true

tags:

- user

- admin

When to Use JSON

  • Web APIs - Standard for REST
  • JavaScript apps - Native support
  • Fast parsing needed
  • Machine-generated data
  • Strict validation required
  • When to Use YAML

  • Configuration files - More readable
  • DevOps - Docker, Kubernetes
  • Comments needed
  • Human-maintained files
  • CI/CD pipelines
  • Conversion

    YAML to JSON (Python)

    import json
    

    import yaml

    with open('config.yaml') as f:

    data = yaml.safe_load(f)

    with open('config.json', 'w') as f:

    json.dump(data, f, indent=2)

    JSON to YAML (Python)

    import json
    

    import yaml

    with open('config.json') as f:

    data = json.load(f)

    with open('config.yaml', 'w') as f:

    yaml.dump(data, f)

    Common Pitfalls

    YAML Whitespace

    # Wrong - inconsistent indent
    

    server:

    port: 8080

    host: localhost # Error!

    # Correct

    server:

    port: 8080

    host: localhost

    YAML Type Coercion

    version: 1.0      # Float
    

    country: NO # Boolean false!

    # Force string

    version: "1.0"

    country: "NO"

    Tool Support

    | Tool | JSON | YAML |

    |------|------|------|

    | Browsers | Native | Library |

    | jq | Yes | No (use yq) |

    | VS Code | Excellent | Excellent |

    Advanced Features

    YAML Anchors

    defaults: &defaults
    

    timeout: 30

    retries: 3

    production:

    <<: defaults

    url: https://api.example.com

    development:

    <<: defaults

    url: http://localhost:3000

    Multiline Strings

    description: |
    

    This is a multiline

    string in YAML

    that preserves newlines

    single_line: >

    This is also multiline

    but becomes single line

    Decision Guide

    Choose JSON for:
    • APIs and data interchange
    • JavaScript applications
    • Performance-critical apps

    Choose YAML for:
    • Configuration files
    • Human readability
    • DevOps workflows

    Real-World Use Cases Compared

    Docker Compose: Why YAML Dominates

    Docker Compose configuration exemplifies why YAML became the standard for DevOps tools. Here's why:

    YAML Version:
    version: '3.8'
    

    services:

    web:

    image: nginx:latest

    ports:

    - "80:80"

    environment:

    - NODE_ENV=production

    volumes:

    - ./html:/usr/share/nginx/html

    depends_on:

    - api

    api:

    build: ./api

    environment:

    DATABASE_URL: postgres://db:5432/myapp

    ports:

    - "3000:3000"

    Same in JSON (rarely used):
    {
    

    "version": "3.8",

    "services": {

    "web": {

    "image": "nginx:latest",

    "ports": ["80:80"],

    "environment": ["NODE_ENV=production"],

    "volumes": ["./html:/usr/share/nginx/html"],

    "depends_on": ["api"]

    },

    "api": {

    "build": "./api",

    "environment": {

    "DATABASE_URL": "postgres://db:5432/myapp"

    },

    "ports": ["3000:3000"]

    }

    }

    }

    Why YAML wins:
    • 30% less syntactic noise (no quotes, commas, braces)
    • Comments for documentation (essential for team configs)
    • Clearer hierarchy through indentation
    • Easier for ops teams to maintain

    REST API Responses: Why JSON Dominates

    Conversely, JSON is the undisputed winner for API responses:

    // Express.js API endpoint
    

    app.get('/api/users/:id', async (req, res) => {

    const user = await User.findById(req.params.id);

    res.json({

    id: user.id,

    name: user.name,

    email: user.email,

    created_at: user.createdAt

    }); // Automatic JSON serialization

    });

    Why JSON wins for APIs:
    • Native browser support (fetch, XMLHttpRequest)
    • Zero ambiguity (YAML's type coercion causes bugs)
    • Faster parsing (10-100x faster than YAML)
    • Smaller payload when minified
    • Industry standard (OpenAPI, JSON Schema)

    Performance Benchmarks

    Parsing Speed Comparison

    Benchmark parsing 1MB file (1000 iterations):

    | Language | JSON | YAML | Winner |

    |----------|------|------|--------|

    | Python | 145ms | 1820ms | JSON (12.5x faster) |

    | Node.js | 42ms | 680ms | JSON (16x faster) |

    | Go | 28ms | 510ms | JSON (18x faster) |

    | Rust | 15ms | 390ms | JSON (26x faster) |

    Takeaway: For high-throughput applications (APIs, data processing), JSON's parsing speed is a decisive advantage.

    File Size Comparison

    Same data in different formats:

    Minified JSON: 2,847 bytes
    

    Formatted JSON: 4,125 bytes

    YAML: 3,210 bytes

    YAML (explicit): 3,890 bytes

    Result: Minified JSON is smallest, YAML is middle ground, formatted JSON is largest.

    Migration Strategies

    Migrating from JSON to YAML

    Common when moving configs from code to infrastructure-as-code:

    # Using yq (YAML processor)
    

    yq eval -P config.json > config.yaml

    # Using Python

    python -c "import json, yaml; print(yaml.dump(json.load(open('config.json'))))"

    Post-migration cleanup:
  • Add comments explaining complex values
  • Use anchors for repeated config blocks
  • Leverage multiline strings for scripts
  • Validate with schema (many YAML tools support JSON Schema)
  • Migrating from YAML to JSON

    Needed when:

    • Building JSON API that reads YAML configs
    • Integrating with JSON-only tools
    • Improving parsing performance

    # Using yq
    

    yq eval -o=json config.yaml > config.json

    # Using Python

    python -c "import json, yaml; json.dump(yaml.safe_load(open('config.yaml')), open('config.json', 'w'), indent=2)"

    Post-migration:
  • Comments are lost—document separately
  • Test for type coercion bugs (YAML's "NO" → false, "1.0" → number)
  • Validate with JSON Schema
  • YAML Gotchas Developers Must Know

    Norway Problem (The "NO" Bug)

    # This is a real bug that has crashed production systems
    

    countries:

    - US

    - GB

    - NO # Interpreted as boolean false!

    # Fix: Quote string values

    countries:

    - "US"

    - "GB"

    - "NO" # Now correctly a string

    Why this happens: YAML spec allows bareword booleans: yes/no, true/false, on/off.

    Version Number Coercion

    version: 1.20  # Becomes float 1.2 (loses trailing zero!)
    

    docker_version: 20.10 # Becomes float 20.1

    # Fix:

    version: "1.20"

    docker_version: "20.10"

    Indentation Errors Are Silent

    server:
    

    host: localhost

    port: 8080

    timeout: 30 # Extra space—creates nested object!

    # Results in:

    # { server: { host: "localhost", port: 8080, " timeout": 30 } }

    Solution: Use YAML linter (yamllint, Prettier) in CI/CD.

    JSON Pitfalls YAML Solves

    No Comments

    JSON's lack of comments forces workarounds:

    {
    

    "_comment": "This is a hack to add comments",

    "database": {

    "_note": "Connection timeout in milliseconds",

    "timeout": 5000

    }

    }

    YAML solution:
    # Proper comments explaining config
    

    database:

    timeout: 5000 # Connection timeout in milliseconds

    Trailing Comma Errors

    JSON is strict about trailing commas:

    {
    

    "name": "Alice",

    "age": 30, // Error! Trailing comma

    }

    YAML doesn't use commas—problem doesn't exist.

    Multi-line Strings Are Ugly

    {
    

    "script": "#!/bin/bash

    set -e

    echo 'Starting'

    ./deploy.sh

    echo 'Done'"

    }

    YAML solution:
    script: |
    

    #!/bin/bash

    set -e

    echo 'Starting'

    ./deploy.sh

    echo 'Done'

    Hybrid Approaches

    Many modern projects use both strategically:

    Example: Terraform + AWS Lambda
    # terraform.tfvars (HCL, similar to YAML)
    

    function_config = {

    memory = 512

    timeout = 30

    }

    Lambda reads JSON at runtime:
    // Lambda function
    

    exports.handler = async (event) => {

    // Event is JSON

    const config = JSON.parse(event.body);

    // ...

    };

    Tools and Ecosystem

    JSON Tools

    • jq: Command-line JSON processor
    • JSON Schema: Validation standard
    • Prettier: Auto-formatting

    YAML Tools

    • yq: jq for YAML
    • yamllint: Linting and validation
    • Kustomize: Kubernetes config management

    Converters

    • yq eval -o=json: YAML → JSON
    • yq eval -P: JSON → YAML
    • Online: json2yaml.com, yaml-online-parser.com

    Conclusion

    Both have their place in modern development. Many projects use JSON for runtime data and YAML for configuration—and that's perfectly fine! Choose based on your specific use case, team preferences, and tooling ecosystem.

    Quick Decision Tree:
    • API responses? → JSON
    • Configuration files? → YAML
    • Browser JavaScript? → JSON
    • Docker/Kubernetes? → YAML
    • Fast parsing needed? → JSON
    • Human editing? → YAML
    • Comments required? → YAML
    • Strict typing? → JSON

    Share:

    Related Articles