subset of YAML spec that parses much quicker.
  • Rust 64.9%
  • Python 35.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
alrie 579a28e65a
All checks were successful
CI / Gate: fmt + clippy (push) Successful in 29s
CI / Perf: comparative benchmark (non-gating) (push) Has been skipped
CI / Gate: build (release, as published) (push) Successful in 13s
CI / Gate: unit tests (push) Successful in 16s
CI / Gate: integration tests (debug) (push) Successful in 16s
CI / Gate: speed floors (push) Successful in 16s
CI / Gate: integration tests (release) (push) Successful in 21s
CI / Package: wheel (windows-x86_64) (push) Successful in 52s
CI / Package: wheel (linux-x86_64) (push) Successful in 47s
CI / Package: wheel (macos-aarch64) (push) Successful in 59s
CI / Package: wheel (macos-x86_64) (push) Successful in 58s
CI / Package: sdist (push) Successful in 18s
CI / Smoke: wheel (py3.11) (push) Successful in 17s
CI / Smoke: wheel (py3.13) (push) Successful in 15s
CI / Smoke: wheel (py3.14) (push) Successful in 15s
CI / Smoke: wheel (py3.8) (push) Successful in 15s
CI / Conformance: differential fuzz (PyYAML + ruamel) (push) Successful in 1m54s
CI / Conformance: character-mutation differential (push) Successful in 39s
CI / Conformance: YAML test suite (ecosystem + JSON oracles) (push) Successful in 21s
CI / Conformance: real-world corpora (PyYAML + libyaml + SchemaStore) (push) Successful in 34s
CI / Perf: anchor scaling invariant (gating) (push) Successful in 18s
CI / Smoke: sdist (build from source) (push) Successful in 38s
CI / Publish to PyPI (push) Has been skipped
Updated spec and readme
2026-08-30 18:24:39 +02:00
.forgejo/workflows Anchors mostly implemented, pre-verification 2026-08-29 23:01:12 +02:00
crates Anchors mostly implemented, pre-verification 2026-08-29 23:01:12 +02:00
docs Fixed more issues found from mutation fuzzing 2026-08-30 15:42:56 +02:00
python/turboyaml Added support for timestamps 2026-08-09 19:20:15 +02:00
scripts Fixed some issues found by mutation fuzzing (mostly invented parses) 2026-08-30 13:32:34 +02:00
src Fixed more issues found from mutation fuzzing 2026-08-30 15:42:56 +02:00
tests Fixed more issues found from mutation fuzzing 2026-08-30 15:42:56 +02:00
.gitignore Improved support for multiline scalars - quoted and plain 2026-08-08 17:02:16 +02:00
Cargo.toml Refactored Repo and CI 2026-08-09 23:55:54 +02:00
LICENSE Implement spec and first rust parser 2026-05-31 13:51:09 +02:00
pyproject.toml Updated toolchain, added support and testing for python 3.14 2026-08-09 17:31:28 +02:00
README.md Updated spec and readme 2026-08-30 18:24:39 +02:00
spec.md Updated spec and readme 2026-08-30 18:24:39 +02:00

TurboYAML

Standard YAML Parser, built for parsing speed. Turboyaml is, to my knowledge, the fastest YAML parser available. Implemented in Rust, with Rust and Python bindings. Supports YAML 1.1 and 1.2. The python release is extensively verified against the currently existing featureset. The Rust bindings are currently less well tested and not released. Currently supports most of the YAML featureset, with some open items. Most notably unsupported today are Tags and Complex / explicit keys and sets. Turboyaml strives to parse exactly in agreement with the Python parser Ecosystem (PyYAML, libyaml, ruamel) and not necessarily with the YAML specification.

Why

Because my everyday work made a faster YAML parser for python necessary. Producing native Python objects (dict / list / str / int / float / bool / date / datetime / None), Turbo is 1827× faster than PyYAML's libyaml C extension (the fastest available Python parser today) and 130170× faster than pure-Python PyYAML — no intermediate Rust tree.

Against the other parsers, grouped by what each one actually produces — ratios are how many times longer the rival takes:

corpus shape → flat deep flow block combo real
Python objects PyYAML CSafeLoader 19.5× 21.4× 26.8× 19.4× 18.3× 18.6×
PyYAML SafeLoader (pure) 171× 163× 167× 166× 133× 156×
Owned Rust tree saphyr YamlOwned 2.57× 2.40× 2.41× 2.66× 2.34× 2.69×
yaml-rust2 2.97× 2.62× 2.56× 2.97× 2.47× 3.04×
Scan, nothing kept libyaml (events) 3.12× 3.59× 2.95× 3.50× 2.52× 4.47×

real is ~960 real third-party configs from SchemaStore; the rest are generated shapes. Every contender parses identical bytes in one process, interleaved so machine drift lands on all of them equally, and each group is timed only over documents every member of that group accepts — TurboYAML never gets to skip what it refuses while a full parser pays for it.

Ratios are compared only within a group. "Parse" means four different amounts of work here (discard the document; borrow from the caller's buffer; build an owned native tree; build CPython objects), and comparing across those is where most published YAML speedups come from. Absolute MB/s is not quoted because it varies ~2.6× with document shape for a single parser — the ratio is the portable number. Reproduce with cargo run -p turboyaml-bench --release --bin gen_corpus && cargo run -p turboyaml-bench --release --bin bench_native && python scripts/bench_python.py && python scripts/bench_report.py.

TurboYAML never silently returns data that differs from a full parser — for anything it can't handle it raises (checked in CI by a differential against PyYAML on unsupported constructs).

Install

pip install rs-turboyaml

The PyPI distribution is rs-turboyaml; the import name is turboyaml.

Usage

Python

import turboyaml

obj = turboyaml.load(text)        # → dict / list / str / int / float / bool /
                                  #   datetime.date / datetime.datetime / None

# Multi-document streams (--- separated) — mirrors yaml.safe_load_all,
# returning an eager list with one element per document:
docs = turboyaml.load_all(text)   # → [doc0, doc1, ...]

# Options, accepted by load and load_all:
#   strict=True       → raise ParseError on duplicate mapping keys
#   version=(1, 2)    → resolve scalars with the YAML 1.2 core schema
#                       (default is 1.1, matching yaml.safe_load)
obj = turboyaml.load(text, version=(1, 2))
try:
    obj = turboyaml.load(text)        # fast path
except turboyaml.TurboYamlError:      # UnsupportedFeatureError or ParseError
    import yaml
    obj = yaml.safe_load(text)        # full parser is the authority

Choosing a schema

turboyaml.load(text)                   # YAML 1.1  (default) → 0123 is 83, yes is True
turboyaml.load(text, version=(1, 2))   # YAML 1.2 core       → 0123 is 123, yes is 'yes'

A %YAML 1.1 / %YAML 1.2 directive at the top of the first document overrides version, matching ruamel. The schema is then fixed for the whole stream; a later directive that disagrees raises rather than switching mid-stream.

The versions differ in grammar as well as resolution — 1.2 relaxed plain scalars in flow context, so [:ab], [a?b] and {: v} parse under version=(1, 2) and are rejected under 1.1, exactly as every 1.1 parser rejects them.

Rust

let value = turboyaml::parse(input)?;             // one document, YAML 1.1
let docs  = turboyaml::parse_all(input)?;         // Vec<Value>, one per document

use turboyaml::YamlVersion;
let v = turboyaml::parse_with(input, /* strict */ false, YamlVersion::V1_2)?;

Not supported

Block and flow collections, every scalar style (plain, quoted, block, and multi-line), and multi-document streams are all supported — The full supported grammar is in spec.md. What TurboYAML deliberately leaves out raises a typed UnsupportedFeatureError, distinct from a malformed-input ParseError, so a fallback layer can be implemented:

  • Tags — !!str, !custom
  • explicit/complex keys (? key)
  • %TAG and reserved directives (%FOO) — %YAML 1.1 and %YAML 1.2 are supported

Correctness

The parser was extensively validated for correctness. Among internal fixed test cases and fuzz testing, it strives for 100% coverage of https://github.com/yaml/yaml-test-suite. It is also extensively verified against lots of real YAML from https://github.com/schemaStore/schemastore.

The basic test strategy is: run all YAML input through turboyaml and the big YAML parsers that define the ecosystem (PyYAML, libyaml, and ruamel at both 1.1 and 1.2) and compare if turboyaml's produced object tree matches the existing parsers.

Where YAML spec and ecosystem differ, turboyaml strives for parity with the ecosystem.

Status

Alpha, but extensively validated. Correctness rests on layered, independent checks, all run in CI:

See spec.md for the normative specification, and docs/architecture.md for how the parser is built and why it is fast (including the optimizations that didn't work).

YAML's three authorities — the spec, the ecosystem, and the test suite — do not always agree. Where they don't, TurboYAML's position and the measurement behind it are in docs/edge_case_decisions.md. The short version: follow the ecosystem over the spec, generally follow ruamel where the ecosystem splits, and raise where any answer would contradict half of it.

Built with PyO3 + maturin.