Tomlyn 2.2.0
Tomlyn

Tomlyn is a high-performance .NET TOML 1.1 parser, round-trippable syntax tree, and System.Text.Json-style object serializer - NativeAOT ready.
Looking for YAML support? Check out SharpYaml.
Note: Tomlyn v1 is a major redesign with breaking changes from earlier versions. It uses a
System.Text.Json-style API withTomlSerializer,TomlSerializerOptions, and resolver-based metadata (ITomlTypeInfoResolver). See the migration guide for details.
✨ Features
System.Text.Json-style API: familiar surface withTomlSerializer,TomlSerializerOptions,TomlTypeInfo<T>- TOML 1.1.0 only: Tomlyn v1 targets TOML 1.1.0 and does not support TOML 1.0
- Source generation: NativeAOT / trimming friendly via
TomlSerializerContextand[TomlSerializable]roots System.Text.Jsonattribute interop: reuse[JsonPropertyName],[JsonIgnore],[JsonRequired],[JsonConstructor],[JsonObjectCreationHandling], and polymorphism attributes- Flexible collection input: opt a collection member into accepting either a single TOML value or an array via
[TomlSingleOrArray] - Allocation-free parsing pipeline: incremental
TomlLexer→TomlParserwith precise spans for errors - Low-level access: full lexer/parser API plus a lossless, trivia-preserving syntax tree (
SyntaxParser→DocumentSyntax) - Reflection control: reflection-based POCO mapping is available, but can be disabled for NativeAOT via a feature switch / MSBuild property
📐 Requirements
Tomlyn targets net8.0, net10.0, and netstandard2.0.
- Consuming the NuGet package works on any runtime that supports
netstandard2.0(including .NET Framework) or modern .NET (net8.0+). - Building Tomlyn from source requires the .NET 10 SDK.
📦 Install
dotnet add package Tomlyn
Tomlyn ships the source generator in-package (analyzers/dotnet/cs) - no extra package needed.
🚀 Quick Start
using Tomlyn;
// Serialize
var toml = TomlSerializer.Serialize(new { Name = "Ada", Age = 37 });
// Deserialize
var person = TomlSerializer.Deserialize<Person>(toml);
Untyped model (TomlTable)
using Tomlyn;
using Tomlyn.Model;
var toml = @"global = ""this is a string""
# This is a comment of a table
[my_table]
key = 1 # Comment a key
value = true
list = [4, 5, 6]
";
var model = TomlSerializer.Deserialize<TomlTable>(toml)!;
var global = (string)model["global"]!;
Console.WriteLine(global);
Console.WriteLine(TomlSerializer.Serialize(model));
Options
using System.Text.Json;
using Tomlyn;
var options = new TomlSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace,
WriteIndented = true,
IndentSize = 4,
MaxDepth = 64,
DefaultIgnoreCondition = TomlIgnoreCondition.WhenWritingNull,
};
var toml = TomlSerializer.Serialize(config, options);
var model = TomlSerializer.Deserialize<MyConfig>(toml, options);
By default, PropertyNamingPolicy is null, meaning CLR member names are used as-is for TOML mapping keys (same default as System.Text.Json).
MaxDepth = 0 uses the built-in default of 64.
PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace matches System.Text.Json: read-only properties are not populated unless you opt into Populate via options or [JsonObjectCreationHandling].
Source Generation
using System.Text.Json.Serialization;
using Tomlyn.Serialization;
public sealed class MyConfig
{
public string? Global { get; set; }
}
[TomlSourceGenerationOptions(
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace)]
[TomlSerializable(typeof(MyConfig))]
internal partial class MyTomlContext : TomlSerializerContext
{
}
var config = TomlSerializer.Deserialize(toml, MyTomlContext.Default.MyConfig);
var tomlOut = TomlSerializer.Serialize(config, MyTomlContext.Default.MyConfig);
Single Value Or Array Collections
using System.Text.Json.Serialization;
using Tomlyn.Serialization;
public sealed class PackagingConfiguration
{
public PackagingConfiguration()
{
RuntimeIdentifiers = new List<string>();
}
[TomlSingleOrArray]
[JsonPropertyName("rid")]
public List<string> RuntimeIdentifiers { get; }
}
With [TomlSingleOrArray], both of these TOML payloads are valid:
rid = "win-x64"
rid = ["win-x64", "linux-x64"]
For mutable read-only collection members, Tomlyn appends into the existing collection instance. Without [TomlSingleOrArray], collection members still require a TOML array.
Reflection Control
Reflection fallback can be disabled globally before first serializer use:
AppContext.SetSwitch("Tomlyn.TomlSerializer.IsReflectionEnabledByDefault", false);
When publishing with NativeAOT (PublishAot=true), the Tomlyn NuGet package disables reflection-based serialization by default.
You can override the default by setting the following MSBuild property in your app project:
<PropertyGroup>
<TomlynIsReflectionEnabledByDefault>true</TomlynIsReflectionEnabledByDefault>
</PropertyGroup>
📖 Documentation
- User guide
- Website (Lunet): https://xoofx.github.io/Tomlyn
🪪 License
This software is released under the BSD-Clause 2 license.
🤗 Author
Alexandre Mutel aka xoofx.
No packages depend on Tomlyn.
.NET 8.0
- No dependencies.
.NET 10.0
- No dependencies.
.NET Standard 2.0
- System.Buffers (>= 4.6.1)
- System.Collections.Immutable (>= 9.0.0)
- System.Text.Json (>= 10.0.2)
| Version | Downloads | Last updated |
|---|---|---|
| 2.3.0 | 2 | 03/29/2026 |
| 2.2.1 | 2 | 03/29/2026 |
| 2.2.0 | 1 | 03/29/2026 |
| 2.1.0 | 1 | 03/29/2026 |
| 2.0.1 | 2 | 03/29/2026 |
| 2.0.0 | 1 | 03/29/2026 |
| 1.2.0 | 1 | 03/29/2026 |
| 1.1.1 | 1 | 03/29/2026 |
| 1.1.0 | 1 | 03/29/2026 |
| 1.0.0 | 1 | 03/29/2026 |
| 0.20.0 | 1 | 03/29/2026 |
| 0.19.0 | 1 | 03/29/2026 |
| 0.18.0 | 1 | 03/27/2026 |
| 0.17.0 | 1 | 03/29/2026 |
| 0.16.2 | 1 | 03/29/2026 |
| 0.16.1 | 1 | 03/29/2026 |
| 0.16.0 | 1 | 03/29/2026 |
| 0.15.1 | 2 | 03/29/2026 |
| 0.15.0 | 2 | 03/29/2026 |
| 0.14.4 | 1 | 03/29/2026 |
| 0.14.3 | 1 | 03/29/2026 |
| 0.14.2 | 1 | 03/29/2026 |
| 0.14.1 | 1 | 03/29/2026 |
| 0.14.0 | 1 | 03/29/2026 |
| 0.13.1 | 1 | 03/29/2026 |
| 0.13.0 | 1 | 03/29/2026 |
| 0.12.1 | 2 | 03/29/2026 |
| 0.12.0 | 1 | 03/29/2026 |
| 0.11.0 | 2 | 03/29/2026 |
| 0.10.2 | 1 | 03/29/2026 |
| 0.10.1 | 1 | 03/29/2026 |
| 0.10.0 | 1 | 03/29/2026 |
| 0.9.1 | 1 | 03/29/2026 |
| 0.9.0 | 1 | 03/29/2026 |
| 0.4.1 | 1 | 03/29/2026 |
| 0.4.0 | 2 | 03/29/2026 |
| 0.3.1 | 1 | 03/29/2026 |
| 0.3.0 | 2 | 03/29/2026 |
| 0.1.2 | 1 | 03/29/2026 |
| 0.1.1 | 1 | 03/29/2026 |
| 0.1.0 | 2 | 03/29/2026 |