Built-in converter catalog
Every type that YamlSerializer handles without a user converter is served by a built-in converter. This page catalogs that set - which .NET types are provisioned, how each appears in YAML on write, and what the read path accepts. Resolution order and the rules for overriding a built-in with your own converter are in Writing converters.
YAML carries the JSON-compatible core scalar kinds - string, integer, float, Boolean, and null - so most everyday .NET types map without any converter at all. The writer emits block-style collections (an empty container falls back to flow [] / {}), and mappings preserve insertion order.
Scalars
| .NET type | YAML representation (write) | Read accepts | Notes |
|---|---|---|---|
string |
string scalar | string | The scalar style (plain / quoted / block) is chosen by the writer and recorded on read by ScalarStyle. |
char |
single-character string | single-character string | A source of any other length raises YamlSerializationException. |
Guid |
string, canonical 36-character form | any Guid.Parse-accepted form |
|
Uri |
string, the original URI text | string | Relative and absolute URIs round-trip. |
bool |
Boolean (true / false) |
Boolean | Under SpecVersion = V1_1, the read path also accepts yes / no / on / off and y / n. |
sbyte byte short ushort int uint long nint |
integer scalar | integer | Checked conversions; a value outside the target type raises YamlSerializationException. |
ulong nuint Int128 UInt128 |
integer scalar, or the invariant decimal text outside the signed 64-bit range | integer or string | A value the writer's signed 64-bit integer surface cannot hold is emitted as its exact decimal text (quoted only when a leading sign would otherwise resolve it numerically) and converts back exactly on read. |
double |
float scalar | float | NaN, +∞, and −∞ write as .nan, .inf, and -.inf. |
float |
float scalar | float | Widens to double on write; narrows on read. |
decimal |
quoted string of the exact invariant text | float scalar or string | Quoted because the exact text would otherwise resolve as a double; the quoting preserves the full decimal precision. |
DateTime |
string, round-trip ("o") ISO-8601 |
string | Read with DateTimeStyles.RoundtripKind. There is no native YAML timestamp type; the value travels as a string scalar. |
DateTimeOffset |
string, round-trip ("o") ISO-8601 |
string | As DateTime, preserving the offset. |
TimeSpan |
string, the invariant TimeSpan form |
string | |
null |
the null scalar (null) |
null, ~, or the empty scalar |
A null member is omitted instead when DefaultIgnoreCondition requests it. |
enum (any) |
string, the member name | string (case-insensitive) or integer | Integers instead of names when WriteEnumsAsStrings = false. |
Note
decimal, DateTime, DateTimeOffset, and TimeSpan are not YAML core-schema kinds - there is no native timestamp or high-precision decimal scalar. The serializer carries each as a string (a decimal is additionally quoted so plain resolution does not turn it back into a double), and the read path parses that string with CultureInfo.InvariantCulture. They therefore round-trip exactly through Serialize / Deserialize, but a value typed object reads back as the underlying string, not as the original CLR type.
The YamlNumberHandling option governs the integer/float boundary on read: Strict (the default) rejects a non-integral or out-of-range float bound to an integer target, while AllowFloatToInteger truncates an integer-valued float toward zero. A plain integer scalar binds to a floating-point target under either policy. Integer scalars are resolved across the YAML radix forms - decimal, hexadecimal (0x), and the 0o octal prefix (plus YAML 1.1's leading-zero octal under SpecVersion = V1_1) - so 0xFF, 0o17, and 255 all bind to the same int.
Structural and document-model types
| .NET type | YAML representation | Notes |
|---|---|---|
arrays, List<T>, IEnumerable<T> and its interfaces, sets, and concrete collections with a parameterless constructor and Add |
sequence | Block-style on write; an empty collection writes as flow []. On read the elements are bound into a List<T> and copied into the requested concrete type. |
IDictionary<TKey,TValue> / IReadOnlyDictionary<TKey,TValue> and concrete dictionaries |
mapping | Written in insertion order. Keys are stringified through Convert.ToString; on read a non-string key type is parsed back (enums by name, other keys via Convert.ChangeType). Mapping keys resolve to unique scalar strings (the Bodu YAML Core Tree Profile) - a duplicate stringified key on write raises YamlSerializationException. |
| plain classes and structs | mapping | The catch-all object converter, consulted last; properties first (reflection order), then public fields when IncludeFields is set. Read requires a public parameterless constructor and sets each writable member. |
object-typed members |
the runtime type's form on write | On read, an object target binds to a loosely-typed graph: a Dictionary<string, object?> for a mapping, a List<object?> for a sequence, and bool / long / double / string / null for scalars - not a YamlElement. |
Nullable<T> |
the underlying value, or the null scalar | A null scalar binds to null; otherwise the value binds as T. |
YamlNode (and YamlObject / YamlArray / YamlValue) |
the node's own kind | Mutable DOM bridge: Deserialize<YamlNode> materializes the value as a node tree (aliases and merge keys already resolved), and a node - standalone or as a member - writes its own kind. |
| YamlElement | the element's own kind | Read produces an element view backed by an internal document that shares the reader's row store - no disposal needed. |
| YamlDocument | the document's root | A deserialized document shares the reader's immutable row store; disposal is optional. |
Fields
Properties map by default. Public fields participate when IncludeFields is true, following the same naming-policy, [PropertyName], and [Ignore] rules as properties:
public sealed class Counter
{
public int Total { get; set; }
public int Retries; // included when IncludeFields is true
}
var options = new YamlSerializerOptions { IncludeFields = true };
string yaml = YamlSerializer.Serialize(new Counter { Total = 3, Retries = 1 }, options);
Total: 3
Retries: 1
Enums
By default an enum is written as its member-name string and read back case-insensitively (or as an integer). Set WriteEnumsAsStrings to false to write the underlying integer instead:
public enum Status { Active, OnHold }
string asString = YamlSerializer.Serialize(new { State = Status.OnHold });
// State: OnHold
var asInt = new YamlSerializerOptions { WriteEnumsAsStrings = false };
string asInteger = YamlSerializer.Serialize(new { State = Status.OnHold }, asInt);
// State: 1
On read an enum binds from a wire name (case-insensitively), or from an integer scalar (through Enum.ToObject), regardless of WriteEnumsAsStrings - the flag affects only the write side. Individual members rename on the wire with the shared StringEnumMemberNameAttribute, honored by the default handling and by the public enum converters:
- YamlStringEnumConverter /
YamlStringEnumConverter<TEnum>- member-name strings with an optional naming policy and an integers-on-read flag; register on the options for every enum, or reference the generic form from a[Converter(...)]attribute. YamlNumberEnumConverter<TEnum>- the underlying numeric value as a YAML integer, regardless ofWriteEnumsAsStrings.
var options = new YamlSerializerOptions();
options.Converters.Add(new YamlStringEnumConverter(NamingPolicy.SnakeCaseLower, allowIntegerValues: false));
// Status.OnHold now serializes as on_hold everywhere.
What YAML does not need a decision for
Unlike TOML, YAML has no decimal-handling or byte[]-handling option: decimal always travels as quoted exact text (above), and a byte[] is treated as an ordinary sequence of byte elements rather than a single encoded scalar. Anything outside the provisioned set - a value type rendered as one scalar, a type with a bespoke mapping shape, or a base64 byte[] - is the job of a custom converter.
Where to go next
- Writing converters - overriding a built-in and the resolution order.
- Mapping attributes - the declarative layer over the converters.
- Using YAML - the walk-through the tables above back up.
- Bodu.Text.Yaml core concepts - the value-mapping summary in the family vocabulary.
- Bodu serializer guides and the Text & Serialization guides.
- API reference - YamlConverter<T>, YamlSerializerOptions, YamlNumberHandling.