Compiler-enforced guardrails for .NET.
Trellis is an opinionated .NET service framework with compiler and analyzer guardrails that make generated code more predictable. It turns typed errors, validated value objects, and composable application pipelines into structure the compiler can enforce — so a whole class of common mistakes fails at build time, whether the code is written by a human or an AI assistant.
📺 Watch the series: youtube.com/@trellisdev — Railway-Oriented Programming, Domain-Driven Design, and more.
Without Trellis
if (string.IsNullOrWhiteSpace(request.Email))
return Results.BadRequest(new { code = "validation.error", detail = "Email is required." });
if (!request.Email.Contains('@'))
return Results.BadRequest(new { code = "validation.error", detail = "Email is invalid." });
return Results.Ok(new User(request.Email.Trim().ToLowerInvariant()));With Trellis
using Trellis.Asp;
using Trellis.Primitives;
return EmailAddress.TryCreate(request.Email)
.Map(email => new User(email))
.ToHttpResponse();- Compiler-enforced guardrails — Roslyn analyzers and types so a whole class of illegal states won't compile; humans and AI stay on the happy path.
Result<T>andMaybe<T>pipelines that make failures explicit — no exceptions for control flow.- Strongly typed value objects that eliminate primitive obsession.
- DDD building blocks:
Aggregate,Entity,ValueObject,Specification, and domain & integration events. - Reliable, crash-safe event delivery via a transactional outbox — events persist atomically with state and relay after commit.
- ASP.NET Core, EF Core, Mediator, HttpClient, FluentValidation, and state-machine integrations.
- AOT-friendly, allocation-conscious APIs built for modern .NET.
AOT: per-package APIs are trim- and AOT-safe;
Trellis.ServiceDefaultsexposes both AOT-safe per-type overloads and assembly-scanning overloads (annotated so the AOT analyzer flags the choice).Trellis.EntityFrameworkCorefollows EF Core's own AOT policy. See the docs for details.
Add the library:
dotnet add package Trellis.Coreusing Trellis;
var result = Result.Ok("ada@example.com")
.Ensure(email => email.Contains('@'),
Error.InvalidInput.ForField("email", "validation.error", "Email is invalid."))
.Map(email => email.Trim().ToLowerInvariant());Or scaffold a full production-ready service — Clean Architecture, API versioning, EF Core, OpenAPI, and tests — with the trellis-asp template:
dotnet new trellis-asp -n MyService| Package | What it gives you |
|---|---|
| Trellis.Core | Result<T>, Maybe<T>, typed errors, and pipeline operators |
| Trellis.Primitives | Ready-to-use concrete value objects plus JSON/tracing infrastructure |
| Trellis.Analyzers | Compile-time guidance for Result, Maybe, and EF Core usage |
| Package | What it gives you |
|---|---|
| Trellis.Asp | Result-to-HTTP mapping, scalar validation, JSON/model binding (bundles the AOT-friendly JSON converter generator), and ASP.NET actor providers (Claims, Entra, Development) |
| Trellis.Authorization | Actor, permission checks, and resource authorization primitives |
| Trellis.Http | HttpClient extensions that stay inside the Result pipeline |
| Trellis.Http.Abstractions | HTTP-aware boundary primitives (HttpError.* cases, EntityTagValue, PreconditionKind, RetryAfterValue, AuthChallenge) shared by Trellis.Asp and Trellis.Http |
| Trellis.Mediator | Result-aware pipeline behaviors for Mediator |
| Trellis.FluentValidation | FluentValidation output converted into Trellis results |
| Trellis.EntityFrameworkCore | EF Core conventions, converters, Maybe queries, and safe save helpers (bundles the Maybe<T> / owned value-object source generator) |
| Trellis.EntityFrameworkCore.Outbox | Transactional outbox that captures domain events in the same transaction and relays them after commit, with domain/integration-event routing |
| Trellis.ServiceDefaults | Opinionated composition builder for wiring Trellis web-service modules in the canonical order |
| Trellis.StateMachine | Stateless transitions that return Result<TState> |
| Trellis.Testing | FluentAssertions extensions for Result<T> and Maybe<T> |
Typical overhead is measured in single-digit to low double-digit nanoseconds—tiny next to a database call or HTTP request. Benchmarks
- 📺 YouTube — @trellisdev: the Trellis video series covering Railway-Oriented Programming, Domain-Driven Design, and more.
- Full documentation
- Getting started
- With vs without Trellis
- API reference
- Training lab + AI consistency benchmark — hand an AI model Trellis, a template, and a spec; let it ship a service in one shot; score against 66 criteria across 6 quality levels.
The Trellis family extends the core framework into multi-service topologies, ready-to-scaffold templates, and operational telemetry. All packages live on nuget.org; all repos share the same MIT license, branch-protected main, and analyzer gates.
xavierjohn/Trellis.Microservices— microservice trust-boundary packages: YARP gateway that mints internal-network JWTs + consumer-side actor provider enforcing a strict claim contract that defends multi-tenant ABAC. ShipsTrellis.Microservices.Abstractions,Trellis.Microservices.AspNetCore,Trellis.Yarp.xavierjohn/Trellis.Microservices.Template—dotnet new trellis-microservicestemplate scaffolding a multi-tenant Project Tracker (YARP gateway + Projects + Members + Aspire AppHost) that demonstrates resource auth, the HideExistence pattern, and the deny-overrides-allow JWT contract.xavierjohn/Trellis.AspTemplate—dotnet new trellis-asptemplate scaffolding a production-ready single-service ASP.NET application with Clean Architecture layout (API + Application + Domain + ACL), API versioning, EF Core, OpenAPI, and test infrastructure.xavierjohn/Trellis.ServiceLevelIndicators— latency SLI metrics library for emitting operation-duration histograms viaSystem.Diagnostics.Metrics+ OpenTelemetry, with rich dimensions (CustomerResourceId,LocationId,Operation,Outcome) and ASP.NET Core + API-versioning integrations.xavierjohn/trellis-training— training lab + AI consistency benchmark: give an AI model Trellis, a template, and a business spec; let it ship a service in one shot; score against 66 criteria across 6 quality levels.
Contributions are welcome. For major changes, please open an issue first and run dotnet test before sending a PR.
