Options

edit

Pass a TomlSerializerOptions to Serialize, Deserialize and TryDeserialize:

var options = new TomlSerializerOptions
{
    PropertyNamingPolicy = TomlNamingPolicy.SnakeCaseLower,
    PreferredObjectCreationHandling = TomlObjectCreationHandling.Replace,
    WriteIndented = true,
    IndentSize = 4,
    MaxDepth = 64,
    DefaultIgnoreCondition = TomlIgnoreCondition.WhenWritingNull,
};

var config = new ServerConfig { Host = "example.com" };
var toml = TomlSerializer.Serialize(config, options);
Assert.Equal("""
    host = "example.com"
    port = 8080

    """, toml);

TomlSerializerOptions is an immutable record: use a with expression to derive an instance from another one. It caches the metadata of your types on first use, so create an instance once, for example in a static readonly field, and reuse it.

With the source generator, set the options with [TomlSourceGenerationOptions] on the context instead: see Source generation.

Name the keys

OptionDefaultEffect
PropertyNamingPolicynullConverts member names to keys. null keeps the C# names, like System.Text.Json.
DictionaryKeyPolicynullConverts dictionary keys when they are written.
PropertyNameCaseInsensitivefalseMatches keys to members ignoring case when reading.

The naming policies are TomlNamingPolicy.CamelCase, PascalCase, SnakeCaseLower, SnakeCaseUpper, KebabCaseLower and KebabCaseUpper. To write your own, derive from TomlNamingPolicy. [TomlPropertyName] sets the key of one member and wins over the policy.

Choose what is written

OptionDefaultEffect
DefaultIgnoreConditionWhenWritingNullSkips null values (WhenWritingNull), also default values (WhenWritingDefault), or nothing (Never).
IncludeFieldsfalseIncludes public fields.
IgnoreReadOnlyPropertiesfalseSkips properties without a public setter when writing. An init property is not read-only.
IgnoreReadOnlyFieldsfalseSkips readonly fields when writing.

TOML has no null: a null member that is not skipped throws a TomlException. [TomlIgnore(Condition = ...)] overrides DefaultIgnoreCondition for one member, including with Never.

Choose how strict reading is

OptionDefaultEffect
UnmappedMemberHandlingSkipSkips keys that match no member, or rejects them (Disallow). Extension data still collects them.
DuplicateKeyHandlingErrorRejects a key assigned twice, or keeps the last value (LastWins). A table defined twice is always rejected.
RespectRequiredConstructorParameterstrueA constructor parameter without a default value must be present. When false, it receives the default value of its type.
RespectNullableAnnotationstrueRejects null in members and constructor parameters declared as non-nullable reference types, when reading and writing.
PreferredObjectCreationHandlingReplaceReplaces object and collection members, or fills the existing instances (Populate). See Mapping members.
MaxInputLength0 (no limit)Maximum length of the input: characters for a string or a TextReader, bytes for a Stream.
MaxDepth0 (64)Maximum nesting depth of tables and arrays.

RespectNullableAnnotations applies before DefaultIgnoreCondition: a null in a non-nullable member throws instead of being skipped, unless the member itself has [TomlIgnore(Condition = TomlIgnoreCondition.WhenWritingNull)] or WhenWritingDefault.

For the limits to set for files you don't trust, see Handling errors.

Layout of the output

OptionDefaultEffect
WriteIndentedfalseIndents the header and the keys of a table once for each table it is nested in.
IndentSize2Number of spaces per level.
NewLineLfLine endings: Lf or CrLf.
MappingOrderOrderThenDeclarationOrder of the members: Declaration, Alphabetical, OrderThenDeclaration or OrderThenAlphabetical. The Order... values honor [TomlPropertyOrder].
InlineTablePolicyNeverWrites nested objects as inline tables (Owner = {Name = "Ada"}): Never, WhenSmall or Always.
TableArrayStyleHeadersWrites arrays of tables with [[name]] headers, or as inline arrays of inline tables (InlineArrayOfTables).
DottedKeyHandlingLiteralWrites a member name or a dictionary key that contains a dot as a quoted key (Literal), or expands it into nested tables (Expand).

Declaration order lists the members of the base types first, then, in each type, the fields and then the properties.

DottedKeyHandling does not change reading: with Expand, the keys are read back as nested tables, so such a model does not round-trip. The keys of a TomlTable are always written as they are.

String styles

StringStylePreferences sets how strings are written:

Formatting attributes

Attributes set the layout of one type or member. They only change how values are written:

[TomlMappingOrder(TomlMappingOrderPolicy.Alphabetical)]
[TomlDottedKeyHandling(TomlDottedKeyHandling.Expand)]
public sealed class FormattedConfig
{
    [TomlTableArrayStyle(TomlTableArrayStyle.Headers)]
    public Package[] Package { get; set; } = [];

    [TomlInlineTable(TomlInlineTablePolicy.Always)]
    public Owner Owner { get; set; } = new();

    [TomlStringStyle(TomlStringStyle.Literal, PreferLiteralWhenNoEscapes = TomlBooleanPreference.True)]
    public string Description { get; set; } = "plain text";
}

public sealed class Owner
{
    public string Name { get; set; } = "";
}
var toml = TomlSerializer.Serialize(new FormattedConfig
{
    Package = [new Package { Name = "core" }],
    Owner = new Owner { Name = "Ada" },
});

Assert.Equal("""
    Description = 'plain text'
    Owner = {Name = "Ada"}
    [[Package]]
    Name = "core"

    """, toml);
AttributeApplies toOverrides
[TomlTableArrayStyle]A collection memberTableArrayStyle
[TomlInlineTable]A memberInlineTablePolicy, for this value only
[TomlStringStyle]A string memberStringStylePreferences
[TomlMappingOrder]A class or a structMappingOrder
[TomlDottedKeyHandling]A class or a structDottedKeyHandling, for the member names of the type

Other options

OptionDefaultEffect
RootValueHandlingErrorWhen the root value is not a table, throws or writes it under RootValueKeyName (WrapInRootKey).
RootValueKeyName"value"The key used by WrapInRootKey.
PolymorphismOptions$type discriminatorThe discriminator key, the handling of unknown types, and derived types registered outside the base type. See Polymorphism.
ConvertersEmptyCustom converters. They win over the built-in converters. See Custom converters.
TypeInfoResolvernullThe source of the metadata, for example a source-generated context.
MetadataStorenullKeeps the comments and the source locations of what is read. See Document model.
SourceNamenullThe file name shown in the TomlException messages.

options.GetTypeInfo<T>() returns the metadata the options resolve for a type, from the converters, the TypeInfoResolver, the built-in types or reflection. TryGetTypeInfo<T>() returns false when there is none.