AvroSourceGenerator 0.7.0
See the version list below for details.
dotnet add package AvroSourceGenerator --version 0.7.0
NuGet\Install-Package AvroSourceGenerator -Version 0.7.0
<PackageReference Include="AvroSourceGenerator" Version="0.7.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="AvroSourceGenerator" Version="0.7.0" />
<PackageReference Include="AvroSourceGenerator"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add AvroSourceGenerator --version 0.7.0
#r "nuget: AvroSourceGenerator, 0.7.0"
#:package AvroSourceGenerator@0.7.0
#addin nuget:?package=AvroSourceGenerator&version=0.7.0
#tool nuget:?package=AvroSourceGenerator&version=0.7.0
Avro Source Generator
![]()
Avro Source Generator is a modern .NET source generator that produces strongly typed C# models from Avro schema, protocol, and IDL files (.avsc, .avpr, and .avdl).
It’s designed to be fast, incremental, and compatible with Apache Avro.
Generated code takes advantage of modern C# language features, including nullable reference types, init-only and required properties, and partial records or classes — ensuring clean, idiomatic C# output.
Prerequisites
- .NET SDK with Roslyn 4.11 or later, such as .NET SDK 8.0.400 or later. Visual Studio builds require Visual Studio 2022 17.11 or later; see the SDK and Visual Studio version mapping.
- Optional runtime integration with one of the following Avro libraries:
- Apache.Avro — official Avro implementation for C#
- Chr.Avro — designed to serve as a flexible alternative to the Apache implementation
You can use the generator without an Avro library, but library-specific features (e.g., ISpecificRecord) won’t be emitted.
Installation & Basic Usage
Install the package:
dotnet add package AvroSourceGenerator
Mark it as a build-only dependency in your .csproj file:
<PackageReference Include="AvroSourceGenerator"
Version="*"
PrivateAssets="all"
ExcludeAssets="runtime" />
Include your .avsc schema files, .avpr protocol files, and .avdl IDL files as AdditionalFiles:
<ItemGroup>
<AdditionalFiles Include="schemas/*.avsc" />
<AdditionalFiles Include="schemas/*.avpr" />
<AdditionalFiles Include="schemas/*.avdl" />
</ItemGroup>
Add a schema file under schemas/, e.g. schemas/user.avsc:
{
"type": "record",
"name": "User",
"namespace": "example",
"fields": [
{ "name": "Name", "type": "string" },
{ "name": "Email", "type": ["null", "string"] },
{ "name": "CreatedAt", "type": { "type": "long", "logicalType": "timestamp-millis" } }
]
}
Or add an Avro IDL file under schemas/, e.g. schemas/user.avdl:
namespace example;
schema UserFromIdl;
/** Example user */
record UserFromIdl {
string Name;
string? Email = null;
timestamp_ms CreatedAt;
}
The file extension selects the parser: .avsc for JSON schemas, .avpr for JSON protocols, and .avdl for IDL.
A protocol supplied as a schema reports AVROSG2000 (schema expected); a schema supplied as a protocol reports AVROSG2001 (protocol expected).
AVDL imports are resolved relative to the importing file. Every imported .avdl, .avsc, or .avpr file,
including transitive imports, must also be included explicitly as an <AdditionalFiles> item. Import cycles,
missing files, and import kind/file type mismatches are reported as errors. Unused imports produce warnings.
Build your project — the generator will create C# types matching your schemas and IDL definitions.
If an input contains errors, the generator reports diagnostics and continues generating independent valid files. Files that depend on invalid schemas are suppressed until those errors are resolved.
Example Output
For the User schema above, targeting Apache.Avro with C# 12 language features produces (abridged):
// <auto-generated/>
#pragma warning disable CS8618, CS8633, CS8714, CS8775, CS8981
#nullable enable
namespace example;
[global::System.CodeDom.Compiler.GeneratedCode("AvroSourceGenerator", "1.0.0.0")]
public partial record User
{
public required string Name { get; init; }
public string? Email { get; init; }
public required global::System.DateTime CreatedAt { get; init; }
}
partial record User : global::Avro.Specific.ISpecificRecord
{
global::Avro.Schema global::Avro.Specific.ISpecificRecord.Schema { get => User._SCHEMA; }
public static readonly global::Avro.Schema _SCHEMA = global::Avro.Schema.Parse("""
{
"type": "record",
"name": "User",
"namespace": "example",
"fields": [
{ "name": "Name", "type": "string" },
{ "name": "Email", "type": ["null", "string"] },
{ "name": "CreatedAt", "type": { "type": "long", "logicalType": "timestamp-millis" } }
]
}
""");
object? global::Avro.Specific.ISpecificRecord.Get(int fieldPos)
{
switch (fieldPos)
{
case 0: return this.Name;
case 1: return this.Email;
case 2: return this.CreatedAt;
default: throw new global::Avro.AvroRuntimeException($"Bad index {fieldPos} in Get()");
}
}
void global::Avro.Specific.ISpecificRecord.Put(int fieldPos, object? fieldValue)
{
switch (fieldPos)
{
case 0:
Set_Name(this, (string)fieldValue!); break;
[global::System.Runtime.CompilerServices.UnsafeAccessor(global::System.Runtime.CompilerServices.UnsafeAccessorKind.Method, Name = "set_Name")]
extern static void Set_Name(global::example.User obj, string value);
case 1:
Set_Email(this, fieldValue! is null ? null : (string)fieldValue!); break;
[global::System.Runtime.CompilerServices.UnsafeAccessor(global::System.Runtime.CompilerServices.UnsafeAccessorKind.Method, Name = "set_Email")]
extern static void Set_Email(global::example.User obj, string? value);
case 2:
Set_CreatedAt(this, (global::System.DateTime)fieldValue!); break;
[global::System.Runtime.CompilerServices.UnsafeAccessor(global::System.Runtime.CompilerServices.UnsafeAccessorKind.Method, Name = "set_CreatedAt")]
extern static void Set_CreatedAt(global::example.User obj, global::System.DateTime value);
default:
throw new global::Avro.AvroRuntimeException($"Bad index {fieldPos} in Put()");
}
}
}
#nullable restore
#pragma warning restore CS8618, CS8633, CS8714, CS8775, CS8981
The exact shape depends on configuration and the selected Avro library.
Samples
- samples/AvroSourceGenerator.ApacheAvro/AvroSourceGenerator.ApacheAvro.csproj shows a minimal
Apache.Avromodel generation flow. - samples/AvroSourceGenerator.ConfluentKafka/AvroSourceGenerator.ConfluentKafka.csproj shows Kafka and Schema Registry integration using Confluent's Avro serializer.
- samples/AvroSourceGenerator.ChrAvroKafka/AvroSourceGenerator.ChrAvroKafka.csproj shows the same Kafka and Schema Registry container workflow using
Chr.Avro.Confluent.
The repository samples use the SDK selected by global.json, currently .NET 10. The Kafka samples also require Docker to run their Kafka and Schema Registry containers.
For example, run the Chr.Avro Kafka sample with:
dotnet run --project samples/AvroSourceGenerator.ChrAvroKafka/AvroSourceGenerator.ChrAvroKafka.csproj
Extending Generated Types
Generated records, classes, and variant interfaces are declared as partial, allowing you to add members or behavior.
Generated enums cannot be extended with partial declarations.
namespace example;
public partial record User
{
public override string ToString() => $"{Name} <{Email}>";
}
Configuration
Configure the generator via MSBuild properties in your .csproj file.
Access Modifier
Generated types are public by default. To make them internal:
<PropertyGroup>
<AvroSourceGeneratorAccessModifier>internal</AvroSourceGeneratorAccessModifier>
</PropertyGroup>
Supported values: public (default), internal.
Record vs Class Generation
By default, types are generated as record when possible. To use class instead:
<PropertyGroup>
<AvroSourceGeneratorRecordDeclaration>class</AvroSourceGeneratorRecordDeclaration>
</PropertyGroup>
Some schema kinds (e.g., fixed, error for Apache.Avro) require classes due to inheritance constraints.
Language Features
By default, the generator matches the consuming project’s C# version. You can target an older version for broader compatibility:
<PropertyGroup>
<AvroSourceGeneratorLanguageFeatures>CSharp7_3</AvroSourceGeneratorLanguageFeatures>
</PropertyGroup>
This disables newer features such as records or nullable reference types.
Supported values are CSharp7_3, CSharp8, CSharp9, CSharp10, CSharp11, CSharp12, CSharp13.
Avro Library Selection
The generator tries to detect the Avro library automatically from referenced packages. You can override this behavior by specifying the target library explicitly.
No Supported Package Detected
Code still generates, but without library-specific features. To suppress the warning and explicitly disable integration:
<PropertyGroup>
<AvroSourceGeneratorAvroLibrary>None</AvroSourceGeneratorAvroLibrary>
</PropertyGroup>
Multiple Supported Packages Detected
Specify one explicitly:
<PropertyGroup>
<AvroSourceGeneratorAvroLibrary>Apache</AvroSourceGeneratorAvroLibrary>
</PropertyGroup>
Supported values:
Auto(default) — detect automaticallyNone— no library-specific codeApache— targetApache.AvroChr— targetChr.Avro
Apache.Avro Logical Type Compatibility
The Apache target preserves unknown logical-type annotations in generated schema JSON and uses the underlying C# type for their fields.
Support depends on the Apache.Avro runtime version: Avro.Schema.Parse in 1.12.1 rejects unknown logical types, which can fail when a generated _SCHEMA field is initialized; 1.12.2 accepts them.
The generator does not check the Apache.Avro version, so use a runtime that can parse the logical types in your schemas.
Parsing and serialization support can differ. Apache.Avro 1.12.2 can parse fixed-backed decimal schemas, but its specific-record writer fails when serializing those decimal values. Successful code generation or schema parsing therefore does not guarantee that every logical type can be serialized or accepted by Schema Registry.
Duplicate Resolution
By default, duplicate schema declarations produce an error.
A duplicate occurs when Avro input files (.avsc, .avpr, or .avdl) declare the same fully qualified schema name.
This behavior can be configured using the following MSBuild property:
<PropertyGroup>
<AvroSourceGeneratorDuplicateResolution>Ignore</AvroSourceGeneratorDuplicateResolution>
</PropertyGroup>
Supported values:
Error(default) — reports a duplicate-schema diagnostic and suppresses affected files; independent valid files still generate.Ignore— keeps the first declaration in the supplied file order and ignores later declarations with the same name in other files.
Duplicate declarations within the same file are always errors, including when Ignore is selected.
Including the same file through equivalent source paths also produces a duplicate-source-path error.
With Ignore, input order determines which definition is used. Use it only when duplicate declarations are intentional and safe.
Reference Resolution
By default, the generator follows Avro's schema resolution rules and requires named schemas to be defined before they are referenced.
If your project keeps related schemas in separate Avro input files, you can defer reference checks until all supported inputs have been read:
<PropertyGroup>
<AvroSourceGeneratorReferenceResolution>Deferred</AvroSourceGeneratorReferenceResolution>
</PropertyGroup>
Supported values:
Strict(default) — references must resolve to an earlier declaration in the same file or to a declaration in the file's transitive AVDL import closureDeferred— unresolved references are collected and resolved after all.avsc,.avpr, and.avdlinputs are read; declared import paths are still validated
Contributing
Contributions are welcome! If you encounter bugs, want to propose features, or improve docs, please open an issue or submit a pull request on GitHub.
License
Licensed under the MIT License.
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.8.0-preview.4.main.16 | 50 | 10/14/2026 |
| 0.8.0-preview.3.main.14 | 55 | 10/13/2026 |
| 0.8.0-preview.2.main.11 | 60 | 10/11/2026 |
| 0.8.0-preview.1.main.7 | 49 | 10/9/2026 |
| 0.7.0 | 523 | 10/1/2026 |
| 0.7.0-preview.4.main.61 | 82 | 9/25/2026 |
| 0.7.0-preview.3.main.32 | 87 | 7/29/2026 |
| 0.7.0-preview.2.main.21 | 102 | 6/2/2026 |
| 0.7.0-preview.1.main.18 | 128 | 3/16/2026 |
| 0.6.0 | 103,619 | 1/29/2026 |
| 0.6.0-preview.3.main.12 | 109 | 1/24/2026 |
| 0.6.0-preview.2.main.10 | 124 | 1/23/2026 |
| 0.6.0-preview.1.main.9 | 110 | 1/23/2026 |
| 0.5.3 | 350 | 1/14/2026 |
| 0.5.2 | 281 | 1/13/2026 |
| 0.5.2-preview.1.duplicate-r... | 1,289 | 12/9/2025 |
| 0.5.1 | 18,284 | 12/7/2025 |
| 0.5.0 | 43,375 | 12/4/2025 |
| 0.4.0 | 1,474 | 11/6/2025 |
| 0.4.0-preview.2 | 191 | 10/15/2025 |