ZeroAlloc.Pipeline
1.4.4
dotnet add package ZeroAlloc.Pipeline --version 1.4.4
NuGet\Install-Package ZeroAlloc.Pipeline -Version 1.4.4
<PackageReference Include="ZeroAlloc.Pipeline" Version="1.4.4" />
<PackageVersion Include="ZeroAlloc.Pipeline" Version="1.4.4" />
<PackageReference Include="ZeroAlloc.Pipeline" />
paket add ZeroAlloc.Pipeline --version 1.4.4
#r "nuget: ZeroAlloc.Pipeline, 1.4.4"
#:package ZeroAlloc.Pipeline@1.4.4
#addin nuget:?package=ZeroAlloc.Pipeline&version=1.4.4
#tool nuget:?package=ZeroAlloc.Pipeline&version=1.4.4
ZeroAlloc.Pipeline
Compile-time pipeline behaviors for .NET source generators: behaviors are discovered at build time and emitted as a static call chain, with no reflection, no allocation per call, and NativeAOT support.
It is the building block behind the pipelines of ZeroAlloc.Mediator and ZeroAlloc.Validation. Write a behavior once against its contracts, or use its Roslyn helpers to give your own generator the same pipeline.
Why ZeroAlloc.Pipeline
- No allocation per call. An emitted three-behavior chain is compiled and asserted at 0 B per call
with
AllocationGateon every test run. Chains that read instance state get a cached form that is also asserted at 0 B per call. - Faster as the pipeline grows. In the same benchmark run, a pre-built delegate chain takes 4.24× the time of the static chain at 3 behaviors and 3.72× at 5. With a single behavior the two are level; see Performance.
- Works under NativeAOT and trimming. The contracts package is
IsAotCompatible, and CI publishes and runs a NativeAOT smoke app on every build. The pipeline is plain static calls, so the trimmer has nothing to keep alive. - Mistakes caught at build time. Rule helpers find a missing or invalid
Handlemethod, duplicateOrdervalues, and a[PipelineBehavior]class that forgotIPipelineBehavior; your generator reports them as compiler diagnostics instead of a pipeline that silently skips a step.
Install
Writing behaviors for a host such as ZeroAlloc.Mediator? You need only the contracts:
dotnet add package ZeroAlloc.Pipeline
Building your own pipeline-aware generator? Add the Roslyn helper library as a private dependency and ship its DLLs next to your generator, as described in Getting Started:
<PackageReference Include="ZeroAlloc.Pipeline.Generators" Version="1.*" PrivateAssets="all" />
Quick start
A behavior is a class with a static Handle method. The host generator finds it at compile time and
calls it directly; there is nothing to register.
using System;
using System.Threading;
using System.Threading.Tasks;
using ZeroAlloc.Pipeline;
[PipelineBehavior(Order = 1)]
public class LoggingBehavior : IPipelineBehavior
{
public static async ValueTask<TResponse> Handle<TRequest, TResponse>(
TRequest request,
CancellationToken ct,
Func<TRequest, CancellationToken, ValueTask<TResponse>> next)
{
Console.WriteLine($"Handling {typeof(TRequest).Name}");
var response = await next(request, ct);
Console.WriteLine($"Handled {typeof(TRequest).Name}");
return response;
}
}
Inside a generator, PipelineEmitter turns the discovered behaviors into the call chain:
using ZeroAlloc.Pipeline.Generators;
PipelineBehaviorInfo[] behaviors =
[
new("global::App.AuthBehavior", order: 1, appliesTo: null, typeParamCount: 2),
new("global::App.LoggingBehavior", order: 2, appliesTo: null, typeParamCount: 2),
];
var shape = new PipelineShape
{
TypeArguments = ["global::App.Ping", "string"],
OuterParameterNames = ["request", "ct"],
LambdaParameterPrefixes = ["r", "c"],
InnermostBodyFactory = depth => $"global::App.PingHandler.Handle(r{depth}, c{depth})",
};
string chain = PipelineEmitter.EmitChain(behaviors, shape);
// global::App.AuthBehavior.Handle<global::App.Ping, string>(request, ct, static (r1, c1) =>
// global::App.LoggingBehavior.Handle<global::App.Ping, string>(r1, c1, static (r2, c2) =>
// global::App.PingHandler.Handle(r2, c2)))
What you get
- Behavior contracts:
IPipelineBehaviorand[PipelineBehavior], with ordering and scoping a behavior to one request type throughAppliesTo. - Your own attribute name: host frameworks subclass
[PipelineBehavior], and discovery follows the inheritance chain. - Incremental discovery: finds behaviors from
ForAttributeWithMetadataNameor a whole compilation. - Chain emission: static lambda chains, plus a cached form for bodies that read instance state.
- Reusable rules: the three validation checks above, mapped to your generator's own diagnostic IDs.
Performance
The static chain that PipelineEmitter.EmitChain generates, against a delegate chain built once at
startup, the fastest runtime-composed alternative. Ratio is mean time relative to the static chain in
the same run; lower is faster.
| Behaviors | Static chain | Pre-built delegate chain | Allocated, both |
|---|---|---|---|
| 1 | 1.00 | 1.03 | 0 B |
| 3 | 1.00 | 4.24 | 0 B |
| 5 | 1.00 | 3.72 | 0 B |
BenchmarkDotNet v0.15.8, .NET 10.0.13, three launches; allocations are exact. Full results, method and caveats: docs/performance.md.
Learn more
- Documentation: pipeline.zeroalloc.net, covering behaviors, shapes, the emitter and discoverer, the diagnostics reference, testing and a cookbook.
- Related packages:
- ZeroAlloc.Mediator: source-generated mediator whose pipeline behaviors are built on this library. Docs: mediator.zeroalloc.net
- ZeroAlloc.Validation: source-generated
validation whose generator is built on this library's helpers, and plugs into Mediator through
ZeroAlloc.Mediator.Validation. Docs: validation.zeroalloc.net - ZeroAlloc.Authorization: policy
authorization that gates Mediator dispatch through a pipeline behavior in
ZeroAlloc.Mediator.Authorization. Docs: authorization.zeroalloc.net - ZeroAlloc.Results: the result type the Mediator validation and authorization behaviors return their failures in. Docs: results.zeroalloc.net
- Contributing: issues and pull requests are welcome on GitHub.
- License: MIT.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages (14)
Showing the top 5 NuGet packages that depend on ZeroAlloc.Pipeline:
| Package | Downloads |
|---|---|
|
ZeroAlloc.Mediator
A zero-allocation mediator library for .NET. Roslyn source generator wires all dispatch at compile time — no reflection, no dictionaries, no virtual dispatch. |
|
|
ZeroAlloc.Validation
A zero-allocation validation library for .NET. Roslyn source generator wires all rule evaluation at compile time — no reflection, no boxing, no runtime overhead. |
|
|
ZeroAlloc.Pipeline.Generators
Roslyn helper library for generator authors — pipeline behavior discovery and emission. |
|
|
ZeroAlloc.Saga
Source-generated long-running process orchestration. Multi-step sagas with compensation, FSM via ZeroAlloc.StateMachine, dispatch via ZeroAlloc.Mediator. Native AOT compatible. |
|
|
Rag.NET
Modular RAG pipeline library for .NET — ingestion and retrieval pipeline builders, self-query, corrective RAG and conversation memory |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.4.4 | 2,918 | 10/21/2026 |
| 1.4.3 | 1,909 | 10/18/2026 |
| 1.4.2 | 1,801 | 10/16/2026 |
| 1.4.1 | 1,260 | 10/15/2026 |
| 1.4.0 | 31,941 | 9/30/2026 |
| 1.3.0 | 1,762 | 9/30/2026 |
| 1.2.5 | 1,887 | 9/28/2026 |
| 1.2.4 | 3,036 | 9/20/2026 |
| 1.2.3 | 422 | 9/20/2026 |
| 1.2.2 | 30,614 | 9/19/2026 |
| 1.2.1 | 2,578 | 5/12/2026 |
| 1.2.0 | 13,649 | 5/3/2026 |
| 1.1.0 | 174 | 5/1/2026 |
| 1.0.1 | 163 | 4/29/2026 |
| 1.0.0 | 173 | 4/28/2026 |
| 0.1.6 | 16,042 | 4/20/2026 |
| 0.1.5 | 183 | 3/22/2026 |
| 0.1.4 | 165 | 3/20/2026 |
| 0.1.3 | 178 | 3/19/2026 |
| 0.1.2 | 180 | 3/17/2026 |