Temp.DDDToolkit.HotChocolate 3.0.0

dotnet add package Temp.DDDToolkit.HotChocolate --version 3.0.0
                    
NuGet\Install-Package Temp.DDDToolkit.HotChocolate -Version 3.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Temp.DDDToolkit.HotChocolate" Version="3.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Temp.DDDToolkit.HotChocolate" Version="3.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Temp.DDDToolkit.HotChocolate" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Temp.DDDToolkit.HotChocolate --version 3.0.0
                    
#r "nuget: Temp.DDDToolkit.HotChocolate, 3.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Temp.DDDToolkit.HotChocolate@3.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Temp.DDDToolkit.HotChocolate&version=3.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Temp.DDDToolkit.HotChocolate&version=3.0.0
                    
Install as a Cake Tool

DDDToolkit

Source generators that remove the repetitive parts of domain driven design in .NET. You declare the intent with an attribute; the generator writes the base type, the equality members, the identifier plumbing, the persistence mapping and the API conversions.

Documentation: dylansnel.github.io/DDDToolkit, the docs/ folder as a site.

[AggregateRoot<Guid>("ORD")]
public partial class Order
{
    public Order(OrderId id, CustomerId customer) : base(id)
    {
        Customer = customer;
        RaiseDomainEvent(new OrderPlaced(id, customer));
    }

    public CustomerId Customer { get; private set; }

    public partial IReadOnlyList<OrderLine> Lines { get; }

    public void AddLine(OrderLine line) => _lines.Add(line);
}

That is the whole declaration. OrderId did not have to be written at all: naming the raw value generates it as an allocation-free identifier with parsing, comparison and JSON support. Order gets its base class, an optimistic concurrency version, a domain event list only it can write to, and a _lines backing field that Entity Framework maps directly while the outside world sees a read-only list.

Declare the identifier yourself when other aggregates, DTOs or API contracts refer to it, which gives it a file of its own to navigate to:

[EntityId<Guid>("ORD")]
public readonly partial record struct OrderId;

[AggregateRoot<OrderId>]
public partial class Order { }

Documentation

Page What it covers
Getting started One module built step by step: an id, a value object, an aggregate, a test, a database, a second module
What the generator writes The generated code for one small aggregate, file by file, and why it is generated
Identifiers [EntityId<T>], struct versus record ids, parsing, prefixes
Value objects [ValueObject], [SingleValueObject<T>], validation and the always-valid twin
Entities and aggregates [Entity<T>], [AggregateRoot<T>], child entities, read-only collections, referencing by id
Invariants Named IInvariant<T> rules and the CheckInvariants() seam, the two stages, and the save that runs them
Domain events Declaring, raising and draining events, and their stable names
Designing aggregates The four rules of aggregate design, and how the toolkit holds each one
Testing The aggregate testing kit: acting on an aggregate and asserting on what it raised
Failure handling Validating without exceptions, and when to throw anyway
Entity Framework Wiring, the generated converters, mapping, concurrency and migrations
Composite keys [KeyPart]: keying a table on more than the id, and carrying that into every owned table
Delivering domain events In-process dispatch or the outbox, and how to choose
Row level security Running a context's queries as the caller, and row access rules written in C# as Postgres policies
Supabase Exporting each module's migrations for supabase db push, as part of the build
Modules [assembly: Module] and the boundary the analyzer checks
Module contracts What a module publishes, why, and where to keep it
Integration events Contracts between modules, the outbox and the inbox, versioning
Transports Carrying integration events out of the process: pgmq, Wolverine, MassTransit, or a sink of your own
GraphQL AddDDDToolkitTypes(), the generated scalar bindings, errors with codes, Relay node ids, one schema over the modules
FluentValidation A value object's rules as a FluentValidation validator, and value objects inside a request validator
Localization Validation errors and invariant violations in the reader's language, looked up by code
Performance The benchmarks behind the struct-versus-record advice, including where they disagree with it
Diagnostics Every DDD000xx diagnostic and how to fix it
Migrating to 3.0 Every 2.x break, with the before and the after

With an AI coding agent

An agent that has never seen the toolkit writes the base class the generator already writes, a settable collection, a sealed value object. Three things teach it otherwise.

A skill. skills/dddtoolkit holds the declarations, the rules the generators enforce, the wiring for Entity Framework and modules, and the fix for every DDD diagnostic. It is an Agent Skill, the format Claude Code, Codex, Cursor and GitHub Copilot read. This repository is also a Claude Code plugin marketplace, so in Claude Code:

/plugin marketplace add DylanSnel/DDDToolkit
/plugin install dddtoolkit@dddtoolkit

For another agent, npx skills add DylanSnel/DDDToolkit installs it, or copy the folder into the agent's skills directory.

The docs as text. The site serves llms.txt, an index of the pages with what each covers, and llms-full.txt, all of them in one file. Every page is also plain Markdown at its own address with .md added, such as docs/invariants.md.

The diagnostics. Every DDD diagnostic carries a link to its entry in Diagnostics, so an IDE opens it from the error list and an agent that reads the build output can follow it.

Packages

Reference DDDToolkit and add the integrations you actually use. Each integration package brings its own generator, so referencing it is all the configuration there is.

For now 3.x is published under Temp. ids: Temp.DDDToolkit, Temp.DDDToolkit.EntityFramework, and so on, each package in the table below with Temp. in front of its name. The nuget.org account that owns the DDDToolkit.* ids cannot publish at the moment, so DDDToolkit there is still 2.0.22. Only the package id is different. The assemblies and namespaces are the ones this page names, so using DDDToolkit; stays as it is.

Package Use it for
DDDToolkit Base types and the core generators. Start here.
DDDToolkit.Abstractions The attributes and marker interfaces alone, for projects that must not reference the runtime.
DDDToolkit.EntityFramework Value converters, model conventions, domain event dispatch, invariant checks, optimistic concurrency, the outbox and the inbox.
DDDToolkit.Messaging.Postgres A pgmq sink, so the outbox enqueues inside the same Postgres transaction that writes the aggregate, and a consumer that reads a queue into the modules' inboxes.
DDDToolkit.Messaging.Wolverine Wolverine as the transport between one process's outbox and another's inbox.
DDDToolkit.Messaging.MassTransit MassTransit 8 as that transport, for those already on it.
DDDToolkit.EntityFramework.Postgres Row level security on any Postgres: each connection a context opens runs as the caller, as PostgREST's do, and [RowAccess] rules written in C# become the policies.
DDDToolkit.EntityFramework.Supabase Your Entity Framework migrations and row access rules written as Supabase migration files by the build, so supabase db push and branching apply them, and a CI build that fails when one is missing.
DDDToolkit.Auth.Supabase Supabase Auth's access tokens validated in any host, against the keys the project publishes, and turned into the caller row level security runs your queries as. No Entity Framework needed.
DDDToolkit.Auth.Supabase.AspNetCore The same in ASP.NET Core: a JWT bearer scheme for Supabase Auth, and each request's user as the caller.
DDDToolkit.Auth.Supabase.AzureFunctions The same in Azure Functions on the isolated worker: a worker middleware that makes each HTTP invocation's user the caller.
DDDToolkit.Mediator One call that dispatches domain events through Mediator instead of a hand-written delegate.
DDDToolkit.FluentValidation A generated validator per value object.
DDDToolkit.Localization Validation errors and invariant violations phrased in the reader's language, through IStringLocalizer.
DDDToolkit.HotChocolate GraphQL scalar bindings and converters for typed identifiers, plus a subscription sink.
DDDToolkit.HotChocolate.Fusion.InMemory One GraphQL schema over a modular monolith: each module a source schema, composed by a Fusion gateway in the process. Needs HotChocolate Fusion 16.6.6 or later.
DDDToolkit.NewtonSoft.Json Newtonsoft converters and a contract resolver that honours [Internal].
DDDToolkit.Testing The aggregate testing kit. A test-only reference; it brings no test framework of its own.
dotnet add package Temp.DDDToolkit

There are five more packages you never reference directly: DDDToolkit.Analyzers and the .EntityFramework, .EntityFramework.Supabase, .FluentValidation and .HotChocolate analyzer packages beside it. Each one carries the generators for its integration and arrives as a dependency of the package above, so adding DDDToolkit.HotChocolate is all it takes to get the GraphQL generator.

Requires .NET 10. The generators themselves target netstandard2.0 and carry no runtime dependencies, so they load in any recent SDK.

The core has no mediator dependency and does not need one: in-process event delivery is a delegate you write, and DDDToolkit.Mediator only saves you writing it. The examples publish through Mediator rather than MediatR because MediatR is commercially licensed from version 13, and this repository prefers dependencies its users can take for free. MediatR still works perfectly well with the toolkit; Delivering domain events shows the delegate to write for it.

What the generators produce

You write You get
[EntityId<T>] on a readonly partial record struct Value, a constructor, Empty/IsEmpty, Parse/TryParse, IParsable<T>, IComparable<T>, explicit conversions, a JSON converter, and CreateUnique/CreateSequential for Guid
[EntityId<T>] on a partial record A reference type identifier: Value, equality over it, Parse/TryParse, CreateUnique/CreateSequential for Guid, and a Valid twin. It has null rather than Empty, and no conversion operators
[SingleValueObject<T>] on a partial record A wrapper with value equality, a Valid twin and validation
[ValueObject] on a partial record, positional or with { get; protected init; } properties Structural equality across the properties you did not exclude, a With(...) for changed copies, and a Valid twin
[Entity<TId>] / [AggregateRoot<TId>] on a partial class The base type, a persistence constructor, a CheckInvariants() seam, GetInvariantViolations() and EnsureInvariants() over it, over any nested IInvariant<T> rules and over every child entity it holds, an EnsureOwnInvariants() / GetOwnInvariantViolations() pair that stops at this object, and an implementation for every get-only partial collection property

Add DDDToolkit.EntityFramework and the same declarations also produce value converters, [Owned] and [ComplexType] annotations, and a single Add<Module>Converters call for your DbContext. Add DDDToolkit.HotChocolate and they produce GraphQL type bindings. You never write that code.

Beyond the declarations

Three things the toolkit does that are not a generated member.

Invariants. State a rule in the generated partial void CheckInvariants() seam, or as a nested IInvariant<T> when it deserves a name, a code and a test of its own. There are two moments to ask. GetInvariantViolations() answers with a list and never throws, for the application that wants to handle "not consistent yet"; EnsureInvariants() throws, and an interceptor runs the same check before every SaveChanges that writes the entity, child entities included, so a broken rule stops the save. Asking the aggregate root asks the whole aggregate, its children too, each violation naming the entity that reported it, so a handler can act on an aggregate and ask what that broke without a DbContext taking part. State nothing and the compiler erases the seam, so an aggregate with no invariants pays nothing.

Integration events. The outbox writes one row per event in the same transaction as the aggregate. A sink delivers it afterwards: to another module in this process, to a pgmq queue, to a GraphQL subscription, or to one you wrote. Versioning and upcasting keep last year's payload readable, and an inbox keyed by message id and consumer makes the receiving side idempotent.

Modules. Mark an assembly [assembly: Module("Ordering")] and name what it publishes with [ModuleContract]. An analyzer then reports where another module reaches past the contract. It says nothing at all until both sides opt in.

Status

Version 3.0 is a breaking release. Identifiers may be structs, domain events moved from Entity to AggregateRoot, IDomainEvent carries an id and a timestamp, aggregates gained an invariant seam and a concurrency version, and misapplied attributes now report a diagnostic instead of silently generating nothing.

Coming from 2.0.22, read Migrating to 3.0: it lists every break with the code you have and the code you need. The changelog has the rest.

License

MIT. See LICENSE.

Product Compatible and additional computed target framework versions.
.NET 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
3.0.0 51 9/27/2026