https://github.com/xoofx/tomlyn
Tomlyn is a TOML parser, validator and authoring library for .NET Framework and .NET Core
https://github.com/xoofx/tomlyn
csharp dotnet dotnet-core toml toml-parser toml-validation
Last synced: 3 months ago
JSON representation
Tomlyn is a TOML parser, validator and authoring library for .NET Framework and .NET Core
- Host: GitHub
- URL: https://github.com/xoofx/tomlyn
- Owner: xoofx
- License: bsd-2-clause
- Created: 2019-02-03T09:54:12.000Z (over 7 years ago)
- Default Branch: main
- Last Pushed: 2025-03-11T10:34:56.000Z (over 1 year ago)
- Last Synced: 2025-04-06T08:01:41.635Z (about 1 year ago)
- Topics: csharp, dotnet, dotnet-core, toml, toml-parser, toml-validation
- Language: C#
- Homepage:
- Size: 458 KB
- Stars: 461
- Watchers: 9
- Forks: 31
- Open Issues: 35
-
Metadata Files:
- Readme: readme.md
- Changelog: changelog.md
- Funding: .github/FUNDING.yml
- License: license.txt
Awesome Lists containing this project
README
# Tomlyn [](https://github.com/xoofx/Tomlyn/actions/workflows/ci.yml) [](https://coveralls.io/github/xoofx/Tomlyn?branch=main) [](https://www.nuget.org/packages/Tomlyn/)

Tomlyn is a high-performance .NET [TOML](https://toml.io/en/) 1.1 parser, round-trippable syntax tree, and `System.Text.Json`-style object serializer - NativeAOT ready.
####
Looking for YAML support? Check out [SharpYaml](https://xoofx.github.io/SharpYaml/).
> **Note**: Tomlyn v1 is a major redesign with breaking changes from earlier versions. It uses a **`System.Text.Json`-style API** with `TomlSerializer`, `TomlSerializerOptions`, and resolver-based metadata (`ITomlTypeInfoResolver`). See the [migration guide](https://xoofx.github.io/Tomlyn/docs/migration) for details.
## ✨ Features
- **`System.Text.Json`-style API**: familiar surface with `TomlSerializer`, `TomlSerializerOptions`, `TomlTypeInfo`
- **TOML 1.1.0 only**: Tomlyn v1 targets [TOML 1.1.0](https://toml.io/en/v1.1.0) and does **not** support TOML 1.0
- **Source generation**: NativeAOT / trimming friendly via `TomlSerializerContext` and `[TomlSerializable]` roots
- **Cross-project polymorphism**: register derived types at runtime or on a source-generated context when base and derived types live in different assemblies
- **`System.Text.Json` attribute 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` → `TomlParser` with 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
```sh
dotnet add package Tomlyn
```
Tomlyn ships the source generator in-package (`analyzers/dotnet/cs`) - no extra package needed.
## 🚀 Quick Start
```csharp
using Tomlyn;
// Serialize
var toml = TomlSerializer.Serialize(new { Name = "Ada", Age = 37 });
// Deserialize
var person = TomlSerializer.Deserialize(toml);
```
### Untyped model (`TomlTable`)
```csharp
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(toml)!;
var global = (string)model["global"]!;
Console.WriteLine(global);
Console.WriteLine(TomlSerializer.Serialize(model));
```
### Options
```csharp
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(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
```csharp
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);
```
### Cross-Project Polymorphism
When a base type lives in one project and derived types live in another, you can register derived types without putting `[TomlDerivedType]` on the base type.
**Reflection path**:
```csharp
using Tomlyn;
var options = new TomlSerializerOptions
{
PolymorphismOptions = new TomlPolymorphismOptions
{
TypeDiscriminatorPropertyName = "kind",
DerivedTypeMappings = new Dictionary>
{
[typeof(Animal)] =
[
new(typeof(Cat), "cat"),
new(typeof(Dog), "dog"),
],
},
},
};
```
**Source generation path**:
```csharp
using Tomlyn.Serialization;
[TomlSerializable(typeof(Animal))]
[TomlDerivedTypeMapping(typeof(Animal), typeof(Cat), "cat")]
[TomlDerivedTypeMapping(typeof(Animal), typeof(Dog), "dog")]
internal partial class MyTomlContext : TomlSerializerContext
{
}
```
Use `TomlPolymorphismOptions.DerivedTypeMappings` and `[TomlDerivedTypeMapping]` additively with existing base-type attributes. Base-type registrations still take precedence when the same discriminator or derived type is registered more than once.
### Single Value Or Array Collections
```csharp
using System.Text.Json.Serialization;
using Tomlyn.Serialization;
public sealed class PackagingConfiguration
{
public PackagingConfiguration()
{
RuntimeIdentifiers = new List();
}
[TomlSingleOrArray]
[JsonPropertyName("rid")]
public List RuntimeIdentifiers { get; }
}
```
With `[TomlSingleOrArray]`, both of these TOML payloads are valid:
```toml
rid = "win-x64"
```
```toml
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:
```csharp
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:
```xml
true
```
## 📖 Documentation
- [User guide](site/readme.md)
- Website (Lunet): https://xoofx.github.io/Tomlyn
## 🪪 License
This software is released under the [BSD-Clause 2 license](https://opensource.org/licenses/BSD-2-Clause).
## 🤗 Author
Alexandre Mutel aka [xoofx](http://xoofx.github.io).