Serde-first YAML for Rust — load config straight into your structs with
#[derive(Deserialize)], with real YAML 1.2 semantics (so NO stays the
string "NO", not false), useful diagnostics, and resource limits built in.
Pure Rust, #![forbid(unsafe_code)].
Static overview graphic. See source notes and benchmark caveats.
[dependencies]
saneyaml = "0.3.0"Then use it:
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)]
struct Config {
name: String,
port: u16,
}
fn main() -> Result<(), saneyaml::Error> {
let cfg: Config = saneyaml::from_str("name: web\nport: 8080\n")?;
assert_eq!(cfg.port, 8080);
let text = saneyaml::to_string(&cfg)?;
println!("{text}");
Ok(())
}Coming from the archived serde_yaml? It's close to a drop-in — see
MIGRATION.md.
Most Rust YAML libraries make you pick one or the other: serde_yaml's
ergonomics (now archived, and YAML 1.1-flavored), or a maintained YAML 1.2
parser like yaml-rust2 or saphyr that hands you a node tree to walk by
hand. saneyaml is serde-first and YAML 1.2-correct.
- Serde-first —
from_str/from_slice/from_reader,to_string/to_writer, and aserde_yaml-styleValue. Deserialize straight into your config structs — no hand-walking a node tree. - YAML 1.2 by default — correct scalar resolution, no "Norway problem":
NO/on/off/yesstay strings. Opt into YAML 1.1 /serde_yaml-style resolution explicitly via schema modes (Core,Json,Failsafe,LegacySerdeYaml). - Diagnostics — line/column, in-document key path (e.g.
server.port), and opt-in source-caret rendering. - Safe on hostile input — unsafe-free, with structural resource limits: input-size, alias-expansion, nesting-depth, scalar-length, and collection-size controls. Reader-backed entrypoints fully buffer bounded input, and these limits are not wall-clock or resident-memory guarantees.
- Streaming and source-preserving edits — pull-based event/document
iterators that bound retained parsed documents while source bytes remain
buffered, plus
edit(...)for path-based config refactors that keep comments, anchors, ordering, and untouched bytes. - Benchmarked — real-world config corpus runs are tracked against
serde_yaml,yaml-rust2, andsaphyr; see BENCHMARKS.md.
Pre-1.0 (0.3.0), MSRV Rust 1.88, and actively maintained. The public API is a
preview surface but is treated as SemVer-visible: breaking changes and MSRV
bumps are explicit, documented release decisions. The road to 1.0 is about
locking the surface down, not expanding it — stability is the goal.
Start with the Guide, or read the same files in-repo: Getting started and the Cookbook. The docs index maps everything else.
- Guides — Getting started · Cookbook · Schema modes · Diagnostics · Untrusted input · Editing files · Streaming
- Migrating — from
serde_yaml - Reference — Compatibility · Architecture · Benchmarks · API docs
- Project — Security · Contributing · Changelog
MIT — see LICENSE.md.
