---
title: "Choosing a C# YAML library"
url: https://recursiveai.org/oneyaml/articles/csharp-yaml-parser/
description: "C# YAML parser libraries compared: YamlDotNet, SharpYaml, VYaml and OneYaml by license, targets, YAML version and API, with the same file read by each."
date: 2026-10-26
author: oneyaml team
---

# Choosing a C# YAML library

C# YAML parser libraries compared: YamlDotNet, SharpYaml, VYaml and OneYaml by license, targets, YAML version and API, with the same file read by each.

October 26, 2026 · oneyaml team

The C# YAML parser most .NET code uses is YamlDotNet, with more than 600 million NuGet downloads and targets from .NET Framework 4.7 to .NET 10. Its README lists YAML 1.2 for the parser but only YAML 1.1 for the emitter, and its typed deserializer reads `yes` as `true`. SharpYaml 3 has a System.Text.Json-style API and reads the YAML 1.2 Core schema. VYaml is built for speed and Unity. OneYaml pairs a System.Text.Json-style serializer with a `YamlDocument` that edits a file and keeps its comments, on .NET 8 and .NET 10. All four are permissively licensed.

Package facts are from each NuGet listing and README, read on 26 October 2026. Behavior was measured by running each package, and the program is below.

## .NET YAML libraries at a glance

| Package, version (date) | License | Targets | API | YAML version, per its docs |
|---|---|---|---|---|
| [YamlDotNet](https://www.nuget.org/packages/YamlDotNet/18.1.0) 18.1.0 (Jun 2026) | MIT | .NET Standard 2.0 and 2.1, .NET Framework 4.7, .NET 8, .NET 10 | `DeserializerBuilder`/`SerializerBuilder`, a `YamlStream` object model, low-level parser and emitter | Parser 1.1 and 1.2, emitter 1.1 ([README](https://github.com/aaubry/YamlDotNet)) |
| [SharpYaml](https://www.nuget.org/packages/SharpYaml/3.16.0) 3.16.0 (Oct 2026) | MIT | .NET Standard 2.0, .NET 8, .NET 10 | System.Text.Json style: `YamlSerializer`, `YamlSerializerOptions`; scanner, parser, emitter and syntax tree | “YAML 1.2 Core Schema”, with Failsafe, JSON and Extended selectable ([README](https://github.com/xoofx/SharpYaml)) |
| [VYaml](https://www.nuget.org/packages/VYaml/1.5.0) 1.5.0 (Oct 2026) | MIT | .NET Standard 2.0 and 2.1, .NET 6, 8, 9; Unity | `[YamlObject]` partial types, source-generated; a UTF-8 parser and emitter | “YAML 1.2 mostly supported” ([README](https://github.com/hadashiA/VYaml)) |
| [OneYaml](https://www.nuget.org/packages/OneYaml/1.2.1) 1.2.1 (Oct 2026) | MIT OR Apache-2.0 | .NET 8, .NET 10 | System.Text.Json style `YamlSerializer`, plus a lossless `YamlDocument` with JSON Pointer edits and patches | 1.2, Core schema |

For native AOT, SharpYaml and OneYaml ship a source generator inside the main package, and VYaml generates code for `[YamlObject]` types. YamlDotNet’s generator is a separate package, [Vecc.YamlDotNet.Analyzers.StaticGenerator](https://www.nuget.org/packages/Vecc.YamlDotNet.Analyzers.StaticGenerator/18.1.0).

## The same file, read by three C# YAML libraries

YAML 1.1 read `yes` as a boolean and a leading zero as octal. YAML 1.2 has only `true` and `false` as booleans, and `0755` is the decimal 755. This program binds both forms to a typed class with each library:

*Program.cs · .NET 10*

```
using System.Text.Json;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
 
var readers = new (string Name, Func<string, Settings> Read)[]
{
    ("YamlDotNet 18.1.0", yaml => new DeserializerBuilder()
        .WithNamingConvention(CamelCaseNamingConvention.Instance)
        .Build()
        .Deserialize<Settings>(yaml)),
    ("SharpYaml 3.16.0", yaml => SharpYaml.YamlSerializer.Deserialize<Settings>(yaml,
        new SharpYaml.YamlSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase })!),
    ("OneYaml 1.2.1", yaml => OneYaml.YamlSerializer.Deserialize<Settings>(yaml)!),
};
 
foreach (var (name, read) in readers)
{
    Console.WriteLine($"{name}: {Show(() => read("enabled: yes").Enabled)}, {Show(() => read("mode: 0755").Mode)}");
}
 
static string Show<T>(Func<T> get)
{
    try { return $"{get()}"; }
    catch (Exception e) { return e.GetType().Name; }
}
 
class Settings
{
    public bool Enabled { get; set; }
    public int Mode { get; set; }
}
```

*Output*

```
YamlDotNet 18.1.0: True, 493
SharpYaml 3.16.0: YamlException, 755
OneYaml 1.2.1: YamlException, 755
```

YamlDotNet reads the file as YAML 1.1: `yes` becomes `true` and `0755` becomes 493. SharpYaml and OneYaml read it as YAML 1.2: `yes` is refused as a boolean, and `0755` is 755. Neither answer is wrong for every project, but you should know which one you get. OneYaml’s error names the line, the column and the JSON Pointer of the value: `The value 'yes' cannot be read as a boolean. (line 1, column 10, path /enabled)`. VYaml isn’t in the run: its typed serializer works through source-generated `[YamlObject]` partial types, which needs a different program.

## Read and edit YAML in C# with OneYaml

*Terminal · NuGet*

```
dotnet new console -o YamlStart
cd YamlStart
dotnet add package OneYaml --version 1.2.1
```

`YamlSerializer.Deserialize<T>` binds YAML to classes and records the way `JsonSerializer` binds JSON, with keys in camel case by default. To change a file that people also edit by hand, parse it into a `YamlDocument`:

*Program.cs · OneYaml 1.2.1 · .NET 10*

```
using OneYaml;
 
const string Src = """
    # Deploy settings
    name: api
    replicas: 2   # raised by the release job
    ports: [80]
    """;
 
// Typed read, the way System.Text.Json works. Keys bind in camel case.
var cfg = YamlSerializer.Deserialize<Config>(Src)!;
Console.WriteLine($"{cfg.Name}: {cfg.Replicas} replicas on {string.Join(", ", cfg.Ports)}");
 
// Edit the same text: only the values you set change.
using var doc = YamlDocument.Parse(Src);
doc.Set("/replicas", 3);
doc.Add("/ports/-", 443);
Console.WriteLine(doc);
 
record Config(string Name, int Replicas, List<int> Ports);
```

*Output*

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

The comment after `replicas` stays, and the new port joins the flow list in its own style. `YamlSerializerOptions` takes naming policies, ignore conditions, converters and the System.Text.Json attributes ([serializer](https://recursiveai.org/oneyaml/csharp/docs/serializer/)). The [getting started guide](https://recursiveai.org/oneyaml/csharp/docs/getting-started/) covers writing YAML and patches, and the [classes recipe](https://recursiveai.org/oneyaml/csharp/cookbook/parse-yaml-into-classes/) and [reading YAML without a class](https://recursiveai.org/oneyaml/csharp/cookbook/read-yaml-without-a-class/) go further.

## What each C# YAML library is for

### YamlDotNet

The default choice for years, and the widest reach: .NET Standard 2.0, .NET Framework and current .NET, plus a Unity Asset Store package. It has builders for the serializer, an object model “similar to XmlDocument”, and low-level parsing and emitting. Its node deserializers can be replaced or extended to change how binding works, as its [samples](https://github.com/aaubry/YamlDotNet/wiki/Samples) show for validation. Choose it for older frameworks, for those extension points, or when the code already works.

### SharpYaml

Version 3 is a redesign with a System.Text.Json-style API, YAML 1.2 Core by default with other schemas selectable, System.Text.Json attribute support, a source generator in the package, and public scanner, parser, emitter and syntax tree APIs. Choose it for System.Text.Json-style code that also has to run on .NET Standard 2.0, or when you need a schema other than Core.

### VYaml

A low-allocation library that works on UTF-8 bytes directly, built for .NET and Unity, including Unity’s own serialized YAML. Choose it for Unity, or when allocation per read matters most.

### OneYaml

The System.Text.Json shape for YAML 1.2, plus edits in place: `YamlDocument` writes a new value in the old one’s style and keeps every other byte, comments included ([edit YAML without losing comments](https://recursiveai.org/oneyaml/articles/edit-yaml-keep-comments/)). It applies RFC 6902 JSON Patch and RFC 7396 Merge Patch to the YAML text ([JSON Patch for YAML](https://recursiveai.org/oneyaml/articles/json-patch-yaml/)), bounds depth, alias expansion and integer size by default with a `YamlLimits.Untrusted` preset ([untrusted input](https://recursiveai.org/oneyaml/csharp/cookbook/untrusted-input/)), and has no dependencies outside .NET. Speed and memory against the other libraries are on the [performance page](https://recursiveai.org/oneyaml/csharp/docs/performance/), which lists the files where OneYaml was slower.

## When OneYaml is not the right fit

- **.NET Framework, .NET Standard or Unity:** OneYaml runs on .NET 8 and .NET 10 only.
- **Comments as data:** `YamlDocument` keeps comments through edits, but it can’t read, add or move them.
- **A public streaming parser:** OneYaml exposes its reader only inside a converter. YamlDotNet, SharpYaml and VYaml have public pull parsers.
- **Schemas other than Core:** OneYaml reads the Core schema only.
- **A long track record:** OneYaml 1.0.0 was released in October 2026.

## How to choose a C# YAML library

- **New code on .NET 8 or later that reads configuration, or edits files people maintain:** OneYaml.
- **System.Text.Json-style code that must also target .NET Standard 2.0:** SharpYaml.
- **Unity:** VYaml or YamlDotNet.
- **Existing YamlDotNet code:** keep it, or swap to `OneYaml.Compat.YamlDotNet`, which keeps the builder calls ([replacing YamlDotNet](https://recursiveai.org/oneyaml/articles/yamldotnet-alternative/)).
- **Existing SharpYaml code:** keep it, or use `OneYaml.Compat.SharpYaml` ([from SharpYaml](https://recursiveai.org/oneyaml/csharp/docs/migrate-sharpyaml/)).

For a fuller side-by-side, including where the others win, see [how OneYaml compares](https://recursiveai.org/oneyaml/csharp/docs/comparison/). All three oneyaml languages are on the [oneyaml home page](https://recursiveai.org/oneyaml/).
