Toolmingo
Guides7 min read

How to Convert YAML to JSON: A Practical Guide

Learn how to convert YAML to JSON in JavaScript, Python, Go, and PHP — with code examples, a quick-reference table, common pitfalls, and when to use each format.

YAML and JSON represent the same underlying data — objects, arrays, strings, numbers, booleans, and null. They're just written differently. YAML is designed for humans to write and read; JSON is what most programs, APIs, and config parsers actually consume. Converting between them is a routine task in DevOps, backend development, and any workflow that touches Kubernetes, CI/CD, or configuration management.

This guide covers the practical differences between the two formats, where conversions go wrong, and how to parse YAML and emit JSON in the four most common server-side languages.

The core difference: same data, different syntax

JSON is strict and machine-readable:

{
  "service": "api",
  "replicas": 3,
  "ports": [8080, 443],
  "env": {
    "NODE_ENV": "production",
    "DEBUG": false
  }
}

YAML is lenient and human-friendly:

service: api
replicas: 3
ports:
  - 8080
  - 443
env:
  NODE_ENV: production
  DEBUG: false
# Comments are allowed here

The underlying data is identical. When you convert YAML to JSON you're not changing the data — you're changing the representation. The key challenges are YAML-specific features that have no JSON equivalent.

What YAML can express that JSON cannot

Before writing conversion code, know what gets lost:

YAML feature JSON equivalent What happens
# comment None Comments are silently dropped
yes / on / true true All become boolean true
no / off / false false All become boolean false
~ or null null Normalised to null
1_000_000 1000000 Underscores removed
Multi-line strings (` , >`) "line1\nline2"
Anchors (&) and aliases (*) Inlined value Expanded inline
Multiple documents (---) Needs special handling Only first doc, or array of docs

The most dangerous conversion is YAML type coercion. The unquoted value 3.10 becomes the number 3.1 (trailing zero dropped). The unquoted value yes becomes true. Country codes like NO (Norway) and ON (Ontario) can silently flip to booleans. Always quote strings that look like booleans or numbers if you control the YAML source.

JavaScript

In Node.js, use the js-yaml library. It's the de facto standard and handles all YAML 1.2 features.

npm install js-yaml
import { load } from "js-yaml";
import { readFileSync } from "fs";

// From a file
const yaml = readFileSync("config.yaml", "utf8");
const data = load(yaml);               // parses YAML → JS object
const json = JSON.stringify(data, null, 2);  // JS object → JSON string
console.log(json);

// From a string
const inline = `
name: deploy
steps:
  - run: npm test
  - run: npm build
`;
console.log(JSON.stringify(load(inline), null, 2));

In the browser, the same js-yaml library works (it's fully isomorphic). Use import { load } from "js-yaml" in a bundled project or load it via a CDN script tag. The Data Converter does exactly this — paste YAML, get JSON instantly, entirely in your browser.

For multi-document YAML files (separated by ---), use loadAll:

import { loadAll } from "js-yaml";

const docs = [];
loadAll(multiDocYaml, (doc) => docs.push(doc));
console.log(JSON.stringify(docs, null, 2));  // array of documents

Python

Python's standard library doesn't include a YAML parser. Install PyYAML:

pip install pyyaml
import yaml
import json

# From a file
with open("config.yaml") as f:
    data = yaml.safe_load(f)          # parses YAML → Python dict

print(json.dumps(data, indent=2))     # Python dict → JSON string

# From a string
yaml_string = """
server:
  host: localhost
  port: 8080
  debug: false
"""
data = yaml.safe_load(yaml_string)
print(json.dumps(data, indent=2))

Always use yaml.safe_load, never yaml.load. The unsafe loader executes arbitrary Python via YAML tags (!!python/object), which is a remote code execution vulnerability if you parse untrusted input.

For multi-document YAML:

import yaml, json

with open("multi.yaml") as f:
    docs = list(yaml.safe_load_all(f))  # list of documents

print(json.dumps(docs, indent=2))

If you need to preserve key insertion order (Python 3.7+ dicts are already ordered), no extra steps are required. Dates parsed from YAML (2024-01-15) become Python datetime.date objects, which are not JSON-serialisable by default. Handle them explicitly:

import datetime

def serialise(obj):
    if isinstance(obj, (datetime.date, datetime.datetime)):
        return obj.isoformat()
    raise TypeError(f"Not serialisable: {type(obj)}")

print(json.dumps(data, indent=2, default=serialise))

Go

Go's standard library has no YAML support. Use gopkg.in/yaml.v3:

go get gopkg.in/yaml.v3
package main

import (
    "encoding/json"
    "fmt"
    "os"

    "gopkg.in/yaml.v3"
)

func yamlToJSON(input []byte) ([]byte, error) {
    var parsed any
    if err := yaml.Unmarshal(input, &parsed); err != nil {
        return nil, fmt.Errorf("yaml parse: %w", err)
    }
    // yaml.v3 produces map[string]any for objects — JSON-serialisable.
    return json.MarshalIndent(parsed, "", "  ")
}

func main() {
    src, _ := os.ReadFile("config.yaml")
    out, err := yamlToJSON(src)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
    fmt.Println(string(out))
}

One gotcha with yaml.v2 (the older library): it unmarshals maps to map[interface{}]interface{}, which encoding/json refuses to serialise. yaml.v3 returns map[string]any instead, which is JSON-compatible. Prefer yaml.v3 for all new code.

PHP

PHP has no built-in YAML parser. Use the symfony/yaml component:

composer require symfony/yaml
<?php

use Symfony\Component\Yaml\Yaml;

// From a file
$data = Yaml::parseFile('config.yaml');
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

// From a string
$yamlString = <<<YAML
database:
  host: localhost
  port: 5432
  name: myapp
YAML;

$data = Yaml::parse($yamlString);
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

For boolean-like strings, Symfony YAML (like all YAML 1.1 parsers) converts yes/no/on/off to booleans. To disable this and get strict YAML 1.2 parsing, pass Yaml::PARSE_CONSTANT:

$data = Yaml::parse($yamlString, Yaml::PARSE_CONSTANT);

Quick reference

Language Parse YAML Emit JSON Watch out for
JavaScript js-yaml: load(str) JSON.stringify(obj, null, 2) Multi-doc: use loadAll
Python PyYAML: yaml.safe_load(f) json.dumps(data, indent=2) Dates not JSON-serialisable; never use yaml.load
Go yaml.v3: yaml.Unmarshal(b, &v) json.MarshalIndent(v, "", " ") Use v3 not v2 (map type)
PHP symfony/yaml: Yaml::parseFile(path) json_encode($data, JSON_PRETTY_PRINT) yes/no → booleans
CLI yq e -o=json . file.yaml yq available via brew/apt
Browser Toolmingo Data Converter No upload, runs locally

6 common pitfalls

1. yes/no silently become booleans. Country codes, feature flag values, and Git branch names can all match YAML 1.1's boolean set. Quote them in the source YAML if you control it, or add explicit handling after parsing.

2. Comments are lost forever. JSON has no comment syntax. Once YAML comments are dropped in conversion, they cannot be recovered by round-tripping back to YAML. Keep the original YAML file if comments matter.

3. Python datetime objects crash json.dumps. YAML dates like 2024-01-15 become Python datetime.date objects, not strings. Pass a default serialiser to json.dumps or convert dates to ISO strings before serialising.

4. Duplicate keys are silently de-duped. YAML technically allows duplicate keys; most parsers keep only the last value. JSON also prohibits duplicate keys. If your YAML source has duplicates (usually a human error), you'll lose data silently.

5. Go yaml.v2 map type breaks JSON. Using the older gopkg.in/yaml.v2 produces map[interface{}]interface{} which encoding/json cannot handle. Switch to yaml.v3 or add a recursive type-conversion function.

6. Numbers with leading zeros are octal in YAML 1.1. The value 0755 in unquoted YAML is parsed as the octal integer 493, not the string "0755". This is a classic pitfall with file permissions in config files. Quote them.

FAQ

Can I convert YAML to JSON without installing a library?

In the browser, yes — the Data Converter runs entirely client-side with no installation needed. On the command line, yq is a single binary that converts YAML to JSON: yq e -o=json . config.yaml.

Will multi-document YAML (separated by ---) work?

Most parsers support it, but you need to call the "load all" variant. In Python it's yaml.safe_load_all(f), in js-yaml it's loadAll(str, callback), and in Go you decode in a loop using yaml.NewDecoder. The result is an array of JSON objects.

What happens to YAML anchors and aliases?

They are resolved before parsing. If &default defines a block and *default references it elsewhere, the parser inlines the referenced value. The output JSON reflects the resolved values, not the anchor/alias syntax.

Why does 3.10 become 3.1 in JSON?

YAML parses 3.10 as the floating-point number 3.1 (trailing zeros are insignificant in numeric literals). JSON then serialises that number as 3.1. If you need to preserve "3.10" as a string — common for version numbers — quote it in the YAML source: version: "3.10".

How do I convert a Kubernetes YAML manifest to JSON?

The same code works. Kubernetes YAML manifests are standard YAML, usually a single document. After parsing and JSON-encoding, the result is a valid Kubernetes JSON manifest that you can apply with kubectl apply -f manifest.json or send to the API directly.

Is it safe to convert YAML online?

Only if the tool runs in your browser. Toolmingo's Data Converter does all processing client-side — your YAML is never uploaded to a server. That matters for manifests referencing internal hostnames, API keys as environment variable names, or any internal service topology.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools