Skip to content

YAMLRocks

Rock-solid YAML for Python, written in Rust.

YAMLRocks is the rock-solid YAML library for Python: a Rust-backed extension that parses and emits YAML fast, follows the YAML 1.2 specification (with a YAML 1.1 compatibility mode), and, unlike PyYAML, round-trips documents while preserving comments, anchors, and formatting. Correct, secure by default, and fast, with Rust at the core (the R in Rock).

The API is small and predictable: loads and dumps for in-memory data, load and dump for files, to_json to export JSON, integer OPT_* flags combined with |, and dumps returning bytes. Reach for a flag only when you need to, and the defaults stay fast and correct.

Created and written by Franck Nijhof, also known as Frenck.

Read the story behind YAMLRocks.

Fast

Parsing runs about 5 to 10 times faster than PyYAML’s C loader, and dumping about 15 to 19 times faster. Native !include resolution over hundreds of files is roughly 18 times faster than a PyYAML constructor.

Correct

A custom YAML 1.2 scanner and parser, exercised against the official YAML test suite plus snapshot and fuzz corpora, and actively tested against thousands of real-world configuration files from dozens of public repositories across many ecosystems. See real-world verification.

Secure

No code execution from tags, safe by default, and hardened against alias bombs and deeply nested input. Includes stay confined to their base directory, so a document cannot reach arbitrary files on disk.

Round-trip

Preserve comments, anchors, scalar styles, flow-versus-block layout, and an explicit --- marker. Edit a value and re-emit with the rest of the document preserved, including unmodified included files.

Async-friendly

Await async_load to parse off the event loop (the native parse releases the GIL, so other tasks keep progressing) and async_dump to write files without blocking it. The extension is built for free-threaded (no-GIL) CPython, too.

Batteries included

YAML 1.1 mode, source-location annotations, native !include resolution with write-back, JSON export, JSON Schema validation (including in-file $schema references), and a PyYAML-compatible shim.

Parse YAML into native Python objects, and serialize them back to bytes:

import yamlrocks
source = """
key: value
list:
- 1
- 2
"""
data = yamlrocks.loads(source)
# {'key': 'value', 'list': [1, 2]}
yamlrocks.dumps(data)
# b'key: value\nlist:\n - 1\n - 2\n'

Edit a value while keeping comments, anchors, and layout untouched:

import yamlrocks
doc = yamlrocks.loads(b"# app config\nname: app # service\nport: 8080\n", option=yamlrocks.OPT_ROUND_TRIP)
doc["port"] = 9090
doc.to_yaml()
# b'# app config\nname: app # service\nport: 9090\n'

Export the same data to JSON with to_json (JSON is valid YAML 1.2, so loads already reads it back):

import yamlrocks
source = """
name: app
ports: [80, 443]
"""
yamlrocks.to_json(yamlrocks.loads(source))
# b'{"name":"app","ports":[80,443]}'

In an asyncio application, await the load so it runs off the event loop thread. The native parse releases the GIL, so other tasks keep progressing:

import asyncio
import yamlrocks
source = """
key: value
list:
- 1
- 2
"""
async def main():
return await yamlrocks.async_loads(source)
asyncio.run(main())
# {'key': 'value', 'list': [1, 2]}

YAMLRocks beats PyYAML’s C loader and leaves pure-Python round-trip libraries far behind. Release-build benchmarks, showing how many times faster YAMLRocks is:

Operationvs PyYAML (C)vs ruamel.yaml

Parse (loads)

~5-10x faster~85-135x faster

Serialize (dumps)

~15-19x faster~155-210x faster

Split config (!include)

~18x fastern/a

See the full comparisons and performance guide. Planning a migration? Start with the migration compatibility matrix.

Trust matters when a parser edits configuration people maintain by hand. YAMLRocks is continuously tested against a reproducible corpus of public YAML repositories across Home Assistant, ESPHome, Ansible, Kubernetes, Docker Compose, GitHub Actions, CloudFormation, GitOps, Helm, OpenAPI, dbt, CircleCI, Serverless, and Tekton. Every standalone YAML file must parse and re-emit byte-for-byte in round-trip mode, and selected Home Assistant configurations are loaded through their full !include graph.

These projects do not endorse or depend on YAMLRocks; their public repositories are used as a compatibility corpus so regressions are caught against YAML that people actually write and maintain. See the real-world verification page for the current corpus and scope.

Round-trip a split configuration, edit a value that lives in an included file, and write only the file that changed back to disk:

import yamlrocks
# Load a Home Assistant config with includes, round-trip mode
doc = yamlrocks.load(
"configuration.yaml",
option=yamlrocks.OPT_ROUND_TRIP | yamlrocks.OPT_INCLUDES,
)
# Edit a value that lives in an included file
doc["automation"][0]["trigger"]["at"] = "07:30:00"
# Save: only the changed file is rewritten, comments and the rest intact
doc.save()