Installation
Packages
Emit is split into focused packages so you only take what you need.
For a typical Kafka + MongoDB setup:
dotnet add package Emitdotnet add package Emit.Kafkadotnet add package Emit.MongoDBRegistering Emit
Everything flows through AddEmit. Call it once in your service registration and chain the providers you need:
builder.Services.AddEmit(emit =>{ emit.AddMongoDb(mongo => { mongo.Configure((sp, ctx) => { ctx.Client = sp.GetRequiredService<IMongoClient>(); ctx.Database = ctx.Client.GetDatabase("my-db"); }) .UseOutbox() .UseDistributedLock(); });
emit.AddKafka(kafka => { kafka.ConfigureClient(cfg => { cfg.BootstrapServers = "localhost:9092"; });
kafka.Topic<string, OrderPlaced>("orders", topic => { topic.Producer(); topic.ConsumerGroup("order-processor", group => { group.AddConsumer<OrderPlacedConsumer>(); }); }); });});AddEmit returns IServiceCollection, so it chains normally with the rest of your registration.
UseOutbox() and UseDistributedLock() are both opt-in. Call UseOutbox() to enable the transactional outbox infrastructure: when active, all producers route through the outbox by default, giving you atomic writes and guaranteed delivery. To bypass the outbox for a specific producer, call UseDirect() on that producer. You can mix outbox and direct producers freely.
UseDistributedLock() is independent of the outbox. You can use Emit purely as a broker integration layer without any persistence package at all.
What gets registered
Emit registers its own background services automatically: the outbox worker, leader election, and offset committer are all BackgroundService implementations managed by the host lifecycle. You don’t start them manually.
All configuration is validated at startup via IValidateOptions<T> with ValidateOnStart(). Misconfiguration surfaces when the application starts, not during a production incident.
DI lifetimes
IEventProducer<TKey, TValue> is registered as scoped. Inject it into controllers, endpoint handlers, or any scoped service. If you need it from a singleton, inject IServiceScopeFactory and create a scope per operation.
See the Quickstart for a full working example.