---
title: "Choosing a Rust YAML crate"
url: https://recursiveai.org/oneyaml/articles/rust-yaml-parser/
description: "Rust YAML parser crates compared: serde_yaml is archived. Its forks, serde-saphyr, saphyr, yaml-rust2, yaml-edit and oneyaml, with status, license and code."
date: 2026-10-26
author: oneyaml team
---

# Choosing a Rust YAML crate

Rust YAML parser crates compared: serde_yaml is archived. Its forks, serde-saphyr, saphyr, yaml-rust2, yaml-edit and oneyaml, with status, license and code.

October 26, 2026 · oneyaml team

A Rust YAML parser used to mean `serde_yaml`, but that crate was archived in March 2024 and is no longer maintained. Today the choice depends on what you need. For the same serde API, use one of its forks: `yaml_serde` from the YAML organization, `serde_yaml_ng` or `serde_norway`. `serde-saphyr` is a serde layer on a pure-Rust parser, `saphyr` and `yaml-rust2` are parsers with their own document types, and `yaml-edit` edits files losslessly. oneyaml puts serde and a lossless, comment-preserving `Document` on one YAML 1.2 parser.

Versions, dates and licenses below are from crates.io on 26 October 2026; descriptions are quoted from each crate’s own README or crates.io page.

## Rust YAML crates at a glance

| Crate, latest version (date) | License | What it is, in its own words |
|---|---|---|
| [serde_yaml](https://crates.io/crates/serde_yaml) 0.9.34+deprecated (Mar 2024) | MIT OR Apache-2.0 | “(This project is no longer maintained.)”; the [repository](https://github.com/dtolnay/serde-yaml) is archived |
| [yaml_serde](https://crates.io/crates/yaml_serde) 0.10.7 (Aug 2026) | MIT OR Apache-2.0 | “the actively maintained fork of serde-yaml, published as `yaml_serde` by the official YAML organization” ([README](https://github.com/yaml/yaml-serde)) |
| [serde_yaml_ng](https://crates.io/crates/serde_yaml_ng) 0.10.0 (May 2024) | MIT | A fork of serde_yaml’s last commit; “This library only follows the YAML specification 1.1.” ([README](https://github.com/acatton/serde-yaml-ng)) |
| [serde_norway](https://crates.io/crates/serde_norway) 0.9.42 (Dec 2024) | MIT OR Apache-2.0 | “A hard-fork of Serde YAML.” ([README](https://github.com/cafkafk/serde-yaml)) |
| [serde-saphyr](https://crates.io/crates/serde-saphyr) 2.0.0 (Oct 2026) | MIT OR Apache-2.0 | “a strongly typed YAML deserializer built on top of `granit-parser`”, fuzz-tested and “designed not to panic on malformed YAML” ([README](https://github.com/bourumir-wyngs/serde-saphyr)) |
| [saphyr](https://crates.io/crates/saphyr) 0.3.2 (Oct 2026) | MIT OR Apache-2.0 | “A fully YAML 1.2 compliant YAML library” (crates.io) |
| [yaml-rust2](https://crates.io/crates/yaml-rust2) 0.13.0 (Sep 2026) | MIT OR Apache-2.0 | “A fully YAML 1.2 compliant YAML parser” (crates.io); the maintained fork of yaml-rust |
| [yaml-edit](https://crates.io/crates/yaml-edit) 0.3.5 (Oct 2026) | Apache-2.0 | “A Rust library for parsing and editing YAML files while preserving formatting, comments, and whitespace”, on a rowan syntax tree ([README](https://github.com/jelmer/yaml-edit)) |
| [oneyaml](https://crates.io/crates/oneyaml) 1.2.0 (Oct 2026) | MIT OR Apache-2.0 | serde and lossless, comment-preserving editing for YAML 1.2 in one crate; no `unsafe` |

Skip `yaml-rust`: RustSec lists it as unmaintained and points to yaml-rust2 ([RUSTSEC-2024-0320](https://rustsec.org/advisories/RUSTSEC-2024-0320.html)). The crates.io description of `serde_yml`, another serde_yaml successor, now begins “DEPRECATED — `serde_yml` is unmaintained”.

What sits under the serde_yaml forks is worth knowing. In `cargo tree`, `serde_yaml_ng` 0.10.0 depends on `unsafe-libyaml` and `yaml_serde` 0.10.7 on `libyaml-rs`, and each of those describes itself on crates.io as “libyaml transpiled to rust by c2rust”. `oneyaml` 1.2.0 depends on its own `oneyaml-core` and `oneyaml-syntax`, plus `serde`, and its code forbids `unsafe`.

## Read YAML into a struct, then edit the file

oneyaml needs Rust 1.85 or newer:

*Terminal · Cargo*

```
cargo add oneyaml@1.2.0 serde -F serde/derive
```

Typed reads use serde, the same `from_str` and `to_string` as serde_yaml. To change a file that people also edit by hand, parse it into a `Document` instead:

*main.rs · oneyaml 1.2.0*

```
use oneyaml::Document;
use serde::Deserialize;
 
#[derive(Debug, Deserialize)]
struct Config {
    name: String,
    replicas: u32,
    ports: Vec<u16>,
}
 
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let src = "\
# Deploy settings
name: api
replicas: 2   # raised by the release job
ports: [80]
";
    // Typed read with serde.
    let cfg: Config = oneyaml::from_str(src)?;
    println!("{cfg:?}");
 
    // Edit the same text: only the touched values change.
    let mut doc = Document::parse(src)?;
    doc.set_path("replicas", 3)?;
    doc.get_mut("ports")?.push(443)?;
    print!("{doc}");
    Ok(())
}
```

*Output*

```
Config { name: "api", replicas: 2, ports: [80] }
# Deploy settings
name: api
replicas: 3   # raised by the release job
ports: [80, 443]
```

The comment after `replicas` stays, and the new port goes into the flow list in its own style. An untouched `Document` writes back byte for byte, and each comment stays with the entry it belongs to, by [numbered rules](https://recursiveai.org/oneyaml/rust/docs/comment-attachment/). Both the serde read and the edit run on one parser, so they can’t disagree about what the file means.

## Errors you can act on

YAML 1.2 is the default, so `yes` is a string, not a boolean. Read into a `bool`, it is an error, and how the error reads matters when a person has to fix the file. The same input through serde_yaml_ng 0.10.0 and oneyaml 1.2.0:

*main.rs · oneyaml 1.2.0 · serde_yaml_ng 0.10.0*

```
use serde::Deserialize;
 
#[derive(Debug, Deserialize)]
#[allow(dead_code)]
struct Service {
    name: String,
    public: bool,
}
 
fn main() {
    let src = "name: web\npublic: yes\n";
 
    if let Err(e) = serde_yaml_ng::from_str::<Service>(src) {
        println!("serde_yaml_ng: {e}\n");
    }
    if let Err(e) = oneyaml::from_str::<Service>(src) {
        print!("oneyaml:\n{}", e.render(src));
    }
}
```

*Output*

```
serde_yaml_ng: public: invalid type: string "yes", expected a boolean at line 2 column 9
 
oneyaml:
error[Y3000]: invalid type: string "yes", expected a boolean; YAML 1.2 reads `yes` as a string (its booleans are `true` and `false`)
 --> 2:9
  |
2 | public: yes
  |         ^^^
  |
  = help: write `true` instead of `yes`, or read the YAML 1.1 booleans (y/n, yes/no, on/off) as booleans with Settings::yaml11_booleans(true) or the Compat::yaml_1_1() preset
  = path: public
  = suggestion (may be incorrect): write the YAML 1.2 boolean `true`: replace `yes` with `true`
```

`Display` is one line for logs. `Error::render` adds a snippet with a stable `Y####` code, the path, and a suggested fix you can apply in code. Files written for YAML 1.1 readers can be read as such with `Compat::yaml_1_1()` or `Settings::yaml11_booleans(true)`. More in the [errors recipe](https://recursiveai.org/oneyaml/rust/cookbook/errors-with-line-and-column/) and the [YAML 1.1 recipe](https://recursiveai.org/oneyaml/rust/cookbook/yaml-1-1-booleans/).

## What each crate is for

### yaml_serde, serde_yaml_ng and serde_norway

The serde_yaml API, maintained. Choose one when you want to keep your code as it is and only need a crate that still gets fixes. yaml_serde’s README shows a one-line rename in `Cargo.toml` that keeps every `use serde_yaml::` line working; [serde_yaml is deprecated: what now](https://recursiveai.org/oneyaml/articles/serde-yaml-deprecated/) walks through it.

### serde-saphyr

A serde deserializer that reads directly into your types, on a pure-Rust parser, built to deny `unsafe` and not to panic on malformed input. Choose it for typed reads when you don’t need to edit files.

### saphyr and yaml-rust2

Parsers with their own document and event types. Choose them when you want to walk YAML events or nodes yourself.

### yaml-edit

A lossless editor that keeps formatting, comments and whitespace, with error recovery. Its README covers parsing and editing, not serde, so for typed reads of the same files you would pair it with a serde crate.

### oneyaml

serde reads and writes, a `Value` with the serde_yaml variant names, and a lossless `Document` that keeps comments through edits, on one parser. A `Document` also applies RFC 6902 JSON Patch and RFC 7396 merge patches to the YAML text, all or nothing ([JSON Patch for YAML](https://recursiveai.org/oneyaml/articles/json-patch-yaml/)). Every read has resource limits, with a `Limits::untrusted()` profile for network input ([untrusted input](https://recursiveai.org/oneyaml/rust/cookbook/untrusted-input/)). Its yaml-test-suite results are on the [conformance page](https://recursiveai.org/oneyaml/rust/docs/conformance/).

## When another crate is the better choice

oneyaml’s own documentation lists these, and its [benchmark tables](https://recursiveai.org/oneyaml/rust/docs/performance/) name every workload where it is slower:

- **Wall-clock serde read speed is what you optimize.** serde_yaml_ng or serde_norway is faster in wall-clock time on some reads, such as typed reads of the OpenAPI-shaped workload. Measure on your own files.
- **Many small edits to many small files.** Below a few kilobytes, yaml-edit’s edits cost fewer instructions and less time.
- **You need something oneyaml doesn’t do:** `no_std`, async I/O, schema validation, templating, or editing a file too large to hold in memory.
- **You need a long production track record.** serde_yaml’s lineage has years of it; oneyaml’s first release was in October 2026.

## How to choose a Rust YAML crate

- **Existing serde_yaml code, no other changes wanted:** yaml_serde, serde_yaml_ng or serde_norway.
- **Typed reads only, pure Rust:** serde-saphyr or oneyaml.
- **You edit files people maintain, or apply patches to them:** oneyaml, or yaml-edit if you don’t need serde.
- **Typed reads and edits of the same files:** oneyaml, which does both on one parser.
- **You walk YAML events or nodes yourself:** saphyr or yaml-rust2.

Start with the [getting started guide](https://recursiveai.org/oneyaml/rust/docs/getting-started/), or read [how oneyaml compares](https://recursiveai.org/oneyaml/rust/docs/comparison/) with the crates above, including where they win. All three oneyaml languages are on the [oneyaml home page](https://recursiveai.org/oneyaml/).
