YAML to JSON in Python

json.dumps(yaml.safe_load(f), indent=2, default=str)

json.dumps(yaml.safe_load(f), indent=2, default=str) reads an open YAML file with PyYAML and writes it as JSON. PyYAML is pip install pyyaml, imported as yaml.

import json, yaml

with open("config.yaml") as f:
    data = yaml.safe_load(f)

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

For this config.yaml:

name: deploy
on: push
region: NO
mode: 0755
released: 2026-10-15
version: 1.10

PyYAML 6.0.3 prints:

{
  "name": "deploy",
  "true": "push",
  "region": false,
  "mode": 493,
  "released": "2026-10-15",
  "version": 1.1
}

YAML 1.1 reads more than you wrote

PyYAML implements YAML 1.1. There, yes, no, on and off are booleans in lowercase, capitalized or all caps, so NO (Norway) is False, and the key on is True, which json.dumps writes as "true". A GitHub Actions workflow’s on: key turns into True that way. A leading zero makes 0755 octal, 493, and an unquoted date becomes a datetime.date. 1.10 is the float 1.1 in every YAML version: quote version numbers.

The converter below reads the same file as YAML 1.2, the version that made JSON a subset of YAML: "on": "push", "region": "NO", "mode": 755, "released": "2026-10-15". Put %YAML 1.1 and a --- line above the file and it reads on, NO and 0755 the 1.1 way too.

To get YAML 1.2 in Python, use ruamel.yaml. With 0.19.1, this prints the same JSON as the tool, character for character:

from ruamel.yaml import YAML

with open("config.yaml") as f:
    data = YAML(typ="safe").load(f)
print(json.dumps(data, indent=2, default=str))

Dates and default=str

Without default=str, the date stops the conversion: TypeError: Object of type date is not JSON serializable. default is called for every object json can’t write, and str turns a date into 2026-10-15. A timestamp such as 2026-10-15T09:30:00Z becomes an aware datetime, and str writes it with a space, "2026-10-15 09:30:00+00:00". For ISO 8601 with the T, pass default=lambda o: o.isoformat().

safe_load, not load

Since PyYAML 6.0, yaml.load(f) without a loader fails: TypeError: load() missing 1 required positional argument: 'Loader'. Don’t fix it with Loader=yaml.Loader. That loader builds any Python object a tag names, so a YAML file can run code:

# evil.yaml: cmd: !!python/object/apply:os.system ["echo pwned"]
yaml.load(open("evil.yaml"), Loader=yaml.Loader)
# pwned
# {'cmd': 0}
yaml.safe_load(open("evil.yaml"))
# yaml.constructor.ConstructorError: could not determine a constructor for the tag 'tag:yaml.org,2002:python/object/apply:os.system'

safe_load builds only plain data: dicts, lists, strings, numbers, booleans, None, dates and a few other standard types.

Several documents

A file with --- between documents makes safe_load raise ComposerError: expected a single document in the stream. list(yaml.safe_load_all(f)) returns one item per document, the JSON array the tool makes from such a file.

From a shell:

python3 -c 'import sys, json, yaml; print(json.dumps(yaml.safe_load(sys.stdin), indent=2, default=str))' < config.yaml

Try it in the JSON ↔ YAML Converter

JSON

1 document · top-level keys: name, on, region, mode, released, version

Runs in your browser. Nothing you enter is sent anywhere.