Silverback 5 Release Notes
5.6.0
Released on 2026-10-29
What's New
- Allow
WaitUntilAllMessagesAreConsumedAsyncto wait for Kafka message processing independently of broker offset commits - Add
WaitUntilAllMessagesAreCommittedAsyncto the Kafka testing helper to explicitly wait for broker offset commits - Upgrade to Confluent.Kafka 2.16.0
Fixes
- Prevent
ObjectDisposedExceptionin IBrokerClientsConnector when application shutdown calls overlap - Fix a race condition that could cause Kafka consumers to stall and exceed the maximum poll interval after a rebalance
- Fix race conditions that could cause message loss or interrupt consumption when a Kafka rebalance or reconnect overlaps with rollback or batch completion
- Prevent Kafka consumers processing partitions together from stalling or skipping messages after a partial cooperative rebalance
- Prevent out-of-order processing and message loss when Kafka consumers stop with full message buffers
- Prevent out-of-order processing and message loss when Kafka consumers retry messages while polling
- Prevent Kafka consumers from polling concurrently and stalling when restarted before a non-blocking stop completes
- Prevent Kafka consumers from stalling when restarted while a non-blocking stop is still processing the buffered messages
- Log failed Kafka offset commits consistently
- Prevent assignment errors and consumption waits failing or returning too early during mocked Kafka rebalances
- Prevent a deadlock in the mocked Kafka when consumers disconnect during a rebalance
- Honor the timeout and the
throwTimeoutExceptionargument inWaitUntilConnectedAsyncof the ITestingHelper - Prevent MQTT consumers from stalling after reconnecting or hanging during disconnect with full message buffers
- Fix uneven distribution of MQTT messages across parallel processing channels
- Allow pending MQTT messages to finish publishing during shutdown and prevent publishing calls from hanging after disconnect
- Prevent canceled MQTT publishing calls from stalling subsequent messages and application shutdown
- Prevent MQTT publishing and application shutdown from hanging when a message is produced synchronously right after an asynchronous produce completes
- Prevent MQTT consumers from stalling or stopping permanently after an unexpected connection loss
- Respect the configured MQTT backpressure limit when buffering messages for processing
- Preserve MQTT sessions across reconnects when persistence is requested without an explicit expiration
- Apply shared MQTT client settings in the order they are configured
- Prevent the DistributedBackgroundService from logging an error when the distributed lock acquisition is canceled during shutdown [#272]
- Fix the event names of the lock related CoreLogEvents
- Prevent the EntityFrameworkLock from causing duplicate key errors when multiple instances start at the same time and ensure the lock is acquired atomically regardless of the database provider [#272]
- Allow the PostgreSqlTableLock to take over expired locks (e.g. left by a crashed instance), prevent duplicate key errors when multiple instances acquire it at the same time and detect when the lock is lost (requires a primary key or unique constraint on the
LockNamecolumn, as created byCreatePostgreSqlLocksTableAsync)
5.5.2
Released on 2026-09-10
Fixes
- Make IBrokerClientsConnector idempotent and safe to call concurrently
5.5.1
Released on 2026-08-26
Fixes
- Restore the NewtonsoftJsonMessageDeserializer<TMessage> stream position after deserialization for backward compatibility
5.5.0
Released on 2026-08-13
What's New
- Reduce NewtonsoftJsonMessageSerializer and NewtonsoftJsonMessageDeserializer<TMessage> allocations
Fixes
- Prevent lazy message stream pushes from hanging when the provider is completed or aborted before the stream is created
5.4.2
Released on 2026-08-04
Fixes
- Correctly route tombstones and regular messages to their respective subscribers regardless of which message is consumed first
5.4.1
Released on 2026-07-29
Fixes
- Prevent a race condition that could cause the BatchSequence constructor to throw an
ObjectDisposedException
5.4.0
Released on 2026-07-28
What's New
- Upgrade to Confluent.Kafka 2.15.0
- Upgrade to MQTTnet 5.2.0
Fixes
- Optimize the shutdown process by stopping consumers in parallel
- Correctly handle subscriber tasks completion
- Resolve rebalance race condition in the mocked Kafka consumer
5.3.3
Released on 2026-06-01
Fixes
- Ensure the batch sequences are completed before disconnecting (a further step in preventing the producer not connected exception during shutdown)
5.3.2
Released on 2026-06-01
Fixes
- Prevent deadlock in the disconnect process
5.3.1
Released on 2026-05-25
Fixes
- Prevent null messages (tombstones) from being forwarded to regular subscribers (subscribing the message type)
- Postpone disconnect to the application stopped lifecycle event to prevent potential issues with the Kafka producer when the application is shutting down
5.3.0
Released on 2026-04-26
What's New
- Upgrade to Confluent.Kafka 2.14.0
Fixes
- Remove the
chunk-message-idheader, which was added by mistake in v5 and introduced an unintended break
5.2.2
Released on 2026-04-24
Fixes
- Handle some potential race conditions in the batch completion and timeout handling
5.2.1
Released on 2026-03-25
Fixes
- Fix a potential deadlock in the batch sequence completion
5.2.0
Released on 2026-03-23
What's New
- Add
WithKafkaTopicandWithMqttTopicextension methods for the InboundEnvelopeBuilder<TMessage> (see Testing) - Add IIntegrationPublisher as an alternative to the
WrapAndPublishextension methods on IPublisher (see Producing Messages)
Fixes
- Ensure that the Kafka AdminClient is initialized with a clean configuration to prevent warnings from being logged
- Fix a race condition potentially preventing the batch sequence from completing successfully when the timeout is reached
5.1.0
Released on 2026-03-04
What's New
- Add IApplicationPublisher as an alternative to the extension methods on IPublisher (see Using the Message Bus)
- Upgrade to Confluent.Kafka 2.13.2
Fixes
- Correctly bind the error handler to the Kafka producer to prevent uncontrolled logging to stderr
5.0.0
Released on 2026-02-22
Silverback 5.0.0 is the most significant update in the library’s history, built on years of user feedback and real-world experience. This release is more than just an upgrade, it’s a complete refactoring that enhances flexibility, performance, and maintainability while laying a strong foundation for future innovations.
Highlights
- An improved configuration API that makes it easier to set up Silverback exactly the way you want, with a more intuitive and consistent syntax. The new fluent API is designed to be more readable and straightforward and to give you more control over the Kafka and MQTT clients that are used under the hood.
services.AddSilverback()
.WithConnectionToMessageBroker(options => options.AddKafka())
.AddKafkaClients(clients => clients
.WithBootstrapServers("PLAINTEXT://localhost:9092")
.AddProducer(producer => producer
.Produce<MyMessage>(endpoint => endpoint
.ProduceTo("my-topic"))
.Produce<MyMessage2>(endpoint => endpoint
.ProduceTo("my-topic-2")))
.AddConsumer(consumer => consumer
.WithGroupId("consumer1")
.AutoResetOffsetToEarliest()
.Consume<MyMessage3>(endpoint => endpoint
.ConsumeFrom("my-topic-3")
.OnError(policy => policy.Retry(3).ThenSkip()))
.Consume<MyMessage4>(endpoint => endpoint
.ConsumeFrom("my-topic-4")
.EnableBatchProcessing(100, TimeSpan.FromSeconds(5))
.OnError(policy => policy.Skip()))));
- The new WrapAndPublish and WrapAndPublishAsync methods allow you to enrich the message envelope with headers, Kafka keys, and other metadata before publishing it.
publisher.WrapAndPublish(
new MyMessage { Content = "Hello, Silverback!" },
envelope => envelope
.AddHeader("custom-header", "custom-value")
.SetKafkaKey("my-key"));
- WrapAndPublishBatch and WrapAndPublishBatchAsync methods extend the WrapAndPublish functionality to support streaming, mapping, and efficient batching with Kafka.
await publisher.WrapAndPublishBatchAsync(
entities,
entity => new MyMessage { Id = entity.Id },
envelope => envelope
.AddHeader("custom-header", "custom-value")
.SetKafkaKey("my-key"));
- The message bus (
IPublisher) has been improved on many levels- is now registered as transient instead of scoped, allowing you to inject it into singleton services
- IEventPublisher, ICommandPublisher, and IQueryPublisher have been replaced by extension methods on
IPublisher, so you don't need multiple dependencies anymore - supports CancellationToken
- supports ValueTask return types
- more performance and reduced allocations
- Many new features to leverage the power of Kafka and MQTT
- Kafka transactions
- Confluent schema registry support
- Kafka consumer cooperative sticky partition assignment strategy
- MQTT 5 request-response
- Redesigned and improved storage packages
- native support for PostgreSQL and SQLite (more to come in the future), as well as Entity Framework
- rethought and rewritten outbox
- client-side offset storage for Kafka
In the following sections, you'll find a more detailed and canonical list of improvements, new features, and breaking changes.
What's New
- Clean up code and increase tests coverage
- Reduce allocations and improve performance in many places (see Performance)
- Register IPublisher as transient instead of scoped to allow injecting it into singleton services
- Add
CancellationTokensupport to the message bus (see Using the Message Bus) - Improve builders for error policies
- Support subscribers returning
ValueTask - Support exponential delay in
RetryErrorPolicy - Add new
AddHeaderandSetKafkaKeyoverloads in the producer endpoint configuration builders for easier and more readable configuration - Introduce typed endpoints registration using
Consume<TMessage>andProduce<TMessage>methods (replacingAddInboundandAddOutbound), making the nested configuration more readable and type-safe (see Producing Messages and Consuming Messages) - Automatically set the typed deserializer according to the message type when using
Consume<TMessage>to configure the endpoint (see Deserializing the Consumed Messages) - Automatically set the typed BinaryMessageDeserializer<TModel> according to the message type when using
Consume<TMessage>to configure the endpoint (see Deserializing the Consumed Messages) - Add full fluent API for Kafka and MQTT configuration (see Producing Messages and Consuming Messages)
- Rewrite storage implementation from scratch and introduce new Silverback.Storage.PostgreSql, Silverback.Storage.Sqlite, Silverback.Storage.EntityFramework and Silverback.Storage.Memory packages (see Storage Integration)
- Refactor transactional outbox adding support for transaction enlistment (even if not using Entity Framework) and improving performance (see Transactional Outbox)
- Improve outbox worker reliability
- Add message filtering in producer configuration (see Producing Messages)
- Improve and simplify tombstone handling (see Producing Tombstone Messages and Consuming Tombstone Messages)
- Add
IInboundEnvelopeextensions to get broker specific metadata such asGetKafkaOffset(),GetKafkaTimestamp(),GetMqttResponseTopic()andGetMqttCorrelationData() - Add
IOutboundEnvelopeextensions to set broker specific metadata such asSetKafkaKey(),SetMqttResponseTopic()andSetMqttCorrelationData() - Add
WrapAndPublishandWrapAndPublishAsyncmethods to IPublisher to allow envelope enrichment (setting headers, kafka key, etc.) and dynamic routing (see Producing Messages) - Add
WrapAndPublishBatchandWrapAndPublishBatchAsyncmethods to IPublisher with the same capabilities ofWrapAndPublishandWrapAndPublishAsync, supporting streaming, mapping, and efficient batching with Kafka (see Producing Messages) - Refactor and improve EntityFrameworkDomainEventsPublisher<TDbContext>
- Improve
ITestingHelperto allow waiting for specific topics to be consumed (see Testing) - Add InboundEnvelopeBuilder<TMessage> and OutboundEnvelopeBuilder<TMessage> to testing packages to help creating test envelopes (see Testing)
- Support Kafka cooperative sticky partition assignment strategy
- Implement transactional client-side offset storage (see Kafka Offset Storage)
- Support Kafka transactions (see Kafka Transactions)
- Add support for Confluent schema registry (Avro, Json, and Protobuf), including mock for in-memory testing
- Add
IgnoreNoMatchingSubscriberssetting to MQTT producer endpoints, to prevent throwing when no subscriber is consuming the produced message - Basic support for MQTT 5 request-response
- Add ConsumerNameFilterAttribute to filter the subscribers by consumer name (replaces KafkaGroupIdFilterAttribute and MqttClientIdFilterAttribute)
- Add new built-in (de-)serializers to support raw
string,Streamandbyte[](see Serializing the Produced Messages and Deserializing the Consumed Messages) - Improve Activity handling for sequences (batch processing, chunking, etc.)
- Upgrade to Confluent.Kafka 2.13.1
- Upgrade to MQTTnet 5.1.0
Breaking Changes
This release includes many breaking changes, as the library underwent a significant refactoring. The following list might be incomplete but should give you an overview of the most important changes:
- Refactored the configuration model and related fluent API, refer to the updated Guides and Samples to see what it looks like in the new version
- Many types, properties, and methods have been renamed or modified to improve readability, consistency, and ergonomics
- Reorganized the configuration namespaces, some extension methods might have been moved to a different namespace, thus requiring a different
using. - Changed the endpoint models and most of the configuration models to records with init-only properties
- Building the endpoints directly is still supported, but the strongly recommended preferred way is to use the fluent API; therefore, from now on the documentation will only show that approach
- Removed all builders interfaces and exposed the actual classes directly (e.g.
ISilverbackBuildertoSilverbackBuilder) AddOutbound/AddInboundmethods have been replaced byAddKafkaClients/AddMqttClientsandProduce/ConsumemethodsConfiguremethod for Kafka clients replaced by configuration methods such asWithBootstrapServers,WithGroupId,WithClientId, etc.IBrokerCallbackandAdd*BrokerCallbackHandlermethods renamed toIBrokerClientCallbackandAdd*BrokerClientCallback- ... (many more changes)
- Split the
IMessageSerializerinterface into IMessageSerializer and IMessageDeserializer - Outbox and all storage-dependent features have been rewritten from scratch, look at the Guides for more details about the new implementation
- Important: the new Entity Framework based outbox works slightly differently than the previous one, and you might need to explicitly begin a transaction
- Exactly once guard has been replaced by the client side offset storage (see Kafka Offset Storage)
- Replaced
IEventPublisher,ICommandPublisher, andIQueryPublisherwith equivalent extension methods on IPublisher (see Using the Message Bus)- Consequently removed the
UseModelconfiguration method
- Consequently removed the
- Removed the whole
IBrokerandIBrokerCollectionconstructs- They are superseded by the
IProducerCollectionandIConsumerCollectioninterfaces, as well as theIBrokerClientCollectionwhich grants access to all underlying broker clients
- They are superseded by the
- Changed some details in IProducer/IConsumer and their implementations
- A lot of methods have been changed to return a
ValueTaskinstead of aTask - Kafka key won't be set to a random
Guidanymore but will benullif not explicitly set - Some changes to the default settings:
- Increased default KafkaConsumerConfiguration.MaxDegreeOfParallelism to 100
- Increased default KafkaConsumerConfiguration.BackpressureLimit to 50
- The JSON deserializers don't use the
x-message-typeheader anymore by default, meaning that you have to explicitly activate the feature to deserialize polymorphic messages (see Deserializing the Consumed Messages) - Changed default NewtonsoftJsonMessageSerializer and NewtonsoftJsonMessageDeserializer<TMessage> typename handling to
TypeNameHandling.None, meaning that you need to explicitly set the type name handling strategy if you want to support polymorphic nested properties - Reverted default and null value handling in NewtonsoftJsonMessageSerializer to Newtonsoft.Json's default
- By default, the
MqttProducerwill not throw an exception anymore if no subscriber is consuming the produced message (can be configured to log a warning, or throw an exception)
- Several changes have been made to ITestingHelper, IKafkaTestingHelper, and IMqttTestingHelper
- Removed the
AddSubscribersmethods allowing to register subscribers via a base type or interface - ... (many more changes)
Migration Guide
Tip
A step-by-step migration guide with before/after examples is available in Migrating from v4 to v5.
The migration from Silverback 4.x.x to 5.x.x is a significant step and requires some effort. The following list is not exhaustive and might not cover all the breaking changes but should give you a good idea of the basic steps:
- Ensure your application targets .NET 10 as starting with v5 Silverback only supports the latest LTS release
- Upgrade all Silverback.* NuGet packages to 5.x.x
- Some namespace usings will need to be adjusted (e.g.,Silverback.Messaging.Configuration → Silverback.Configuration)
- Migrate the endpoints configuration to the new broker clients configuration (an example of the new fluent API can be found in the Highlights section above)
- Replace usage of
IEventPublisher,ICommandPublisher, andIQueryPublisherwith the related extension methods on the basic IPublisher or the consolidated IApplicationPublisher (introduced in v5.1.0) if you prefer a more testable approach (see also Using the Message Bus) - If using the outbox, adjust the DbContext / database schema and review transaction handling: you might need to explicitly begin a transaction and enlist it in the publisher to keep application changes and outbox messages atomic (see also Transactional Outbox)
Deprecation Notice
The support for RabbitMQ has been dropped in this release and the Silverback.Integration.RabbitMQ package has been deprecated. See Deprecation notice: packages to be deprecated in Silverback v5.