---
title: "Write YAML tokens in C#"
url: https://recursiveai.org/oneyaml/csharp/cookbook/write-yaml-tokens/
description: "Write YAML tokens in C# with a complete runnable example, real output and the behavior to check before using the result. Free, open-source .NET code."
version: "1.2.1"
---

# Write YAML tokens in C#

**OneYaml** is a free, open-source YAML library for .NET from Recursive AI. MIT or Apache-2.0, no native dependencies.

[NuGet](https://www.nuget.org/packages/OneYaml) · [GitHub](https://github.com/recursive-ai-oss/oneyaml-csharp) · [Docs](https://recursiveai.org/oneyaml/csharp/docs/) · [Download example (.zip)](https://recursiveai.org/oneyaml/csharp/cookbook/write-yaml-tokens/write-yaml-tokens.zip)

Write YAML key-value pairs and lists directly into a UTF-8 buffer.

```shell
dotnet add package OneYaml
```

The package targets .NET 8 and .NET 10; the download runs on [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0).

```csharp
using OneYaml;
using System.Buffers;
using System.Text;

var buffer = new ArrayBufferWriter<byte>();
var emitter = new Utf8YamlEmitter(buffer);
emitter.WriteStartMapping();
emitter.WritePropertyName("ports");
emitter.WriteStartSequence();
emitter.WriteNumberValue(80);
emitter.WriteEndSequence();
emitter.WriteEndMapping();
Console.Write(Encoding.UTF8.GetString(
    buffer.WrittenSpan));
```

```text
ports:
  - 80
```

Unzip [the example](https://recursiveai.org/oneyaml/csharp/cookbook/write-yaml-tokens/write-yaml-tokens.zip), then `dotnet run`.

## The full program

The full program writes two ports and deserializes the emitted text into a typed record. No input files are needed. Unbalanced or out-of-order emitter calls throw `InvalidOperationException`.

```csharp
using OneYaml;
using System.Buffers;
using System.Text;

var buffer = new ArrayBufferWriter<byte>();
var emitter = new Utf8YamlEmitter(buffer);
emitter.WriteStartMapping();
emitter.WritePropertyName("ports");
emitter.WriteStartSequence();
emitter.WriteNumberValue(80);
emitter.WriteNumberValue(443);
emitter.WriteEndSequence();
emitter.WriteEndMapping();
string yaml = Encoding.UTF8.GetString(buffer.WrittenSpan);
Console.Write(yaml);
var service = YamlSerializer.Deserialize<Service>(yaml)!;
Console.WriteLine($"Parsed ports: {string.Join(", ", service.Ports)}");

record Service(int[] Ports);
```

`dotnet run` prints:

```text
ports:
  - 80
  - 443
Parsed ports: 80, 443
```

## Variations

Strings that look like another scalar type are quoted automatically:

```csharp
using OneYaml;
using System.Buffers;
using System.Text;

var buffer = new ArrayBufferWriter<byte>();
var emitter = new Utf8YamlEmitter(buffer);
emitter.WriteStringValue("true");
Console.Write(Encoding.UTF8.GetString(buffer.WrittenSpan));
```

```text
'true'
```

## Related recipes

- [Write YAML from objects](https://recursiveai.org/oneyaml/csharp/cookbook/write-yaml/)
- [Read YAML without a class](https://recursiveai.org/oneyaml/csharp/cookbook/read-yaml-without-a-class/)

## The short answer

Create a `Utf8YamlEmitter` with an `IBufferWriter<byte>`, then write balanced mapping and sequence start/end calls. Use `WritePropertyName` for a mapping key and a `Write…Value` method for its value. Decode the written bytes with UTF-8 when you need a .NET string. The program above then parses that string, so it checks both the emitted structure and the values it contains.

This is useful when you already have a stream of values or want precise control over which nodes you write. If you already have a class representing the output, `YamlSerializer.Serialize` avoids spelling out the structure token by token.

## How do I generate a YAML file?

The emitter produces bytes, not a file path. After the full program has filled `buffer`, save its contents:

```csharp
File.WriteAllBytes("out.yaml", buffer.WrittenSpan.ToArray());
```

This writes `out.yaml` with the same content the program prints:

```yaml
ports:
  - 80
  - 443
```

No YAML source file is required: the literal port numbers in the program are its input.

For each mapping, write a property name followed by exactly one value. That value can itself be a sequence or mapping. In the program, `ports` owns a sequence, and each number belongs to that sequence. Close the sequence before closing the outer mapping. You do not need to add document markers, indentation or newlines yourself.

Ending a collection that is not open, writing a value where a key is required, or writing a second tag on the same node throws `InvalidOperationException`. Treat that as an error in the calling code, rather than as malformed user YAML. The [emitter guide](https://recursiveai.org/oneyaml/csharp/docs/reader-emitter/) documents this order checking.

## How do I write YAML tags in C#?

Call `WriteTag` before writing the node it applies to. The tag argument is the resolved tag: the core string tag is `tag:yaml.org,2002:str`, not the shorthand `!!str`. Anchors and aliases also have explicit emitter methods. These are node properties, not mapping keys; do not put them into `WritePropertyName` and expect tag semantics.

For a tagged scalar, use the variation’s `buffer` and `emitter` setup with a fresh buffer, then replace its write and print calls with:

```csharp
emitter.WriteTag("!ref");
emitter.WriteStringValue("defaults");
Console.Write(Encoding.UTF8.GetString(buffer.WrittenSpan));
```

```text
!ref defaults
```

Use the value method matching your intended type. The variation writes the string `true`, so the emitter quotes it to keep it a string on reading. Writing a boolean value instead would express a boolean. Letting the emitter decide quoting keeps strings from silently changing type.
