← Blog

Kafka C#/.NET Clients: Confluent.Kafka vs KafkaFlow

Kafka libraries for C# and .NET fall into two layers. Clients connect to brokers and implement the Kafka protocol; this guide covers Confluent.Kafka and Dekaf. Frameworks manage how your application consumes and handles messages. The ones covered here, KafkaFlow, MassTransit, Wolverine, Silverback, and CAP, all build on Confluent.Kafka.

For most services, start with Confluent.Kafka, Confluent's client built on the native librdkafka library. KafkaFlow adds parallel workers, middleware, and consumer lifecycle management. By default, though, it does not retry a message whose handler fails.

This guide compares clients, frameworks, and stream-processing libraries. It shows what each library handles, what your application must still configure, and how deployment requirements, failure handling, licensing, and maintenance affect the choice. Capabilities are checked against specific releases.

Quick decision

SituationBest starting pointWhy
Plain producer or consumer in a service or workerConfluent.KafkaConfluent's official client and by far the most downloaded. By default, a record's offset can be committed before your code processes it, so disable automatic offset storage and store offsets only after successful processing.
No native library in the deploymentDekafPure C# with async consumption through IAsyncEnumerable. Consumer groups require Kafka 4.0+, and 1.0.0 shipped in July 2026.
Consumers that need parallel workers, middleware, and typed handlersKafkaFlowRuns the consumer pipeline on Confluent.Kafka, with parallel workers that preserve per-key order by default. Configure retries explicitly: by default, a failed message is logged and its offset committed. See its maintenance signals.
Existing MassTransit applicationMassTransit Kafka riderAdds Kafka topics to the bus, consumers, and sagas you already run. Version 9 requires a commercial license; version 8 stays Apache-2.0, with security patches announced through 2026.
Database updates must reliably produce Kafka eventsWolverine or CAPA transactional outbox stores business changes and outgoing messages in one database transaction, then publishes them to Kafka. Wolverine also offers a durable inbox for Kafka listeners.
Stateful stream processing: aggregations, joins, windowsStreamiz.Kafka.NetA Kafka Streams-style library on Confluent.Kafka. See Stream processing in .NET.

For Avro, Protobuf, or JSON Schema, check each library's Schema Registry integration. Confluent.Kafka and Dekaf have their own serializer packages; framework support varies, as the comparison tables below show.

Confluent.Kafka vs KafkaFlow: client or framework?

KafkaFlow is not an alternative to Confluent.Kafka. KafkaFlow 4.2.0 depends on Confluent.Kafka and uses it for every connection to Kafka. The real choice is whether your code or a framework owns the consumer loop.

Here is who handles each concern:

ConcernConfluent.Kafka 2.16.0KafkaFlow 4.2.0
Consumer loopYour code calls Consume in a loop, usually in a hosted worker.KafkaFlow polls and dispatches each message through middleware to your handler.
ConcurrencyYour code decides how to process records concurrently, and must preserve per-key order if it dispatches them to several workers.Several workers per consumer (WithWorkersCount). The default BytesSum strategy sends messages with the same partition key to the same worker, preserving their order.
Offset commitsAuto-commit every 5 s. By default, a record's offset is stored when Consume returns it, before your code runs.Tracks completed records per partition and periodically commits offsets without advancing past unfinished records. Records completed but not committed before a crash may be replayed.
Send retrieslibrdkafka retries retriable send failures until delivery.timeout.ms (5 minutes by default) expires. Idempotence is off by default.The same: KafkaFlow producers use Confluent.Kafka.
Processing retriesYour code.None by default: the exception is logged, and the message is completed and its offset stored. Add KafkaFlow.Retry for retries.
SerializationBuilt-in serializers for common types, custom ISerializer and IDeserializer implementations, or Confluent's Schema Registry serdes.Serializer middleware for JSON, Protobuf, and Schema Registry Avro, Protobuf, and JSON Schema.
Lifecycle and operationsYour code.Hosted-service integration, an admin web API, and a dashboard.

KafkaFlow is useful when you need a managed consumer pipeline, parallel workers, and ordered offset tracking. For a simple sequential consumer, using Confluent.Kafka directly is often enough.

Kafka .NET clients compared

Capabilities verified against each release's documentation and packages: 9 Oct 2026

AreaConfluent.Kafka 2.16.0Dekaf 1.23.3
ImplementationWraps librdkafka 2.16.0 from the librdkafka.redist packagePure C#
Target frameworks.NET Framework 4.6.2, .NET Standard 2.0, .NET 8, .NET 10.NET Standard 2.0, .NET 8, .NET 10
Native binarieslinux-x64 and linux-arm64 (glibc and Alpine musl), linux-s390x, osx-x64, osx-arm64, win-x64, win-x86None; Native AOT tested on .NET 10 linux-x64
Consume APIBlocking Consume(CancellationToken)ConsumeAsync returning IAsyncEnumerable
Consumer groupsClassic, including cooperative-sticky; KIP-848 with GroupProtocol.ConsumerKIP-848 only; requires Kafka 4.0+
Default offset commitsAutomatic every 5 s; offsets stored as soon as Consume returns a recordAutomatic every 5 s; a record becomes eligible for commit when a sequential consume loop requests the next record
TransactionsYesYes
SecurityTLS/mTLS; SASL PLAIN, SCRAM, GSSAPI (platform-dependent), OAUTHBEARER with built-in OIDC; AWS MSK IAM through AWS.MSK.Auth tokensTLS/mTLS; SASL PLAIN, SCRAM, GSSAPI (.NET 8 and 10), OAUTHBEARER; AWS MSK IAM
Default partitioner for non-empty keysCRC32 (consistent_random)Murmur2, Java-compatible
Schema RegistryAvro, Protobuf, and JSON Schema via separate Confluent.SchemaRegistry.Serdes.* packagesAvro, Protobuf, and JSON Schema; payload validation for JSON Schema requires optional Dekaf.SchemaRegistry.Json
LicenseApache-2.0MIT

KIP-848 moves partition assignment to the broker and became generally available in Kafka 4.0. Confluent.Kafka supports both the classic and consumer group protocols, with classic as the default in 2.16.0. Dekaf implements only the consumer protocol and documents Kafka 4.0 or later as the broker baseline for its consumer groups. If your application must consume through consumer groups on Kafka 3.x, use Confluent.Kafka.

Confluent.Kafka

Confluent.Kafka is Confluent's .NET client. Release 2.16.0 (7 Oct 2026) depends on librdkafka 2.16.0, so the protocol behavior comes from that C library.

Capabilities and limitations

  • API: ProduceAsync returns a delivery result; to reduce per-message Task overhead, Produce takes a delivery callback instead. Consume is blocking, so run the loop on a dedicated thread or in a hosted worker that does not block application startup.
  • Native library: librdkafka.redist ships the binaries listed above and loads the matching one at runtime, including a separate build for Alpine. On other platforms, such as Windows on ARM64, you must supply librdkafka yourself and load it with Library.Load.
  • Consumer commits: The client commits every 5 seconds by default and can commit a record that your code has not finished. For at-least-once processing, keep auto-commit enabled, set EnableAutoOffsetStore = false, and call StoreOffset after successful processing. Retry or durably route a failed record before storing a later offset in the same partition; with parallel handlers, also avoid storing past records that are still in progress.
  • Consumer groups: With the classic protocol, set PartitionAssignmentStrategy = PartitionAssignmentStrategy.CooperativeSticky for incremental rebalances. KIP-848 has been production-ready since Confluent.Kafka 2.12.0; enable it with GroupProtocol = GroupProtocol.Consumer on Kafka 4.0+. Under this protocol, partition assignment is controlled by the broker.
  • Default partitioner: consistent_random hashes keys with CRC32. Set Partitioner = Partitioner.Murmur2Random for Java-compatible key-to-partition mapping. The frameworks below inherit this default unless you change the producer configuration.
  • Authentication: OAUTHBEARER supports OIDC directly with SaslOauthbearerMethod.Oidc. For AWS MSK IAM, use AWS's AWS.MSK.Auth token generator with an OAUTHBEARER refresh handler.
  • Maintenance: The repository snapshot shows 22 merged PRs in 90 days and 14 accounts merging PRs in the past year, alongside 381 open issues with a median age of 5.5 years.

When to choose: Choose Confluent.Kafka for a direct producer or consumer when native librdkafka binaries fit your deployment. It is also the practical starting point for consumer-group workloads on Kafka 3.x. For consumers, plan for the blocking API and store offsets only after successful processing.

Dekaf

Dekaf is a pure C# client that does not need librdkafka. The latest release is 1.23.3 (9 Oct 2026). The coverage below comes from the project's documentation and feature support matrix; test it against your brokers.

Capabilities and limitations

  • API: Producers and consumers are created with fluent builders such as Kafka.CreateProducer<TKey, TValue>(). ConsumeAsync returns a long-lived IAsyncEnumerable, and LINQ-style extensions filter and batch records.
  • Consumer groups: KIP-848 only, with Kafka 4.0+ as the documented baseline. Share consumers (KIP-932) offer queue-style processing with per-record acknowledgements and require Kafka 4.2+ with share groups enabled on the broker.
  • Consumer commits: Auto-commit runs every 5 seconds by default. A record becomes eligible for commit when a sequential consume loop requests the next record; catching an exception and continuing also advances this position. For explicit control, use WithAutoOffsetStore(false) and call StoreOffset after successful processing. Retry or durably route failed records before advancing the stored offset past them in the same partition.
  • Default partitioner: Non-empty serialized keys use Java-compatible Murmur2 hashing; null or empty keys use uniform sticky partitioning. ConsistentRandom provides Confluent.Kafka-compatible CRC32 mapping for non-empty keys, given identical key bytes and partition counts.
  • Compression: Gzip is built in. LZ4, Zstd, and Snappy come as separate packages, implemented in C# and registered explicitly by both producers and consumers.
  • Extras: Separate packages add hosted services, dependency injection, a transactional outbox, Schema Registry, OpenTelemetry, and in-memory test doubles. These extension packages target .NET 8 and .NET 10.
  • Maintenance: The repository was created on 21 Jan 2026, 1.0.0 shipped on 4 Jul 2026, and it has published 39 GitHub releases in the past year. The repository snapshot shows 1,295 commits and 1,197 merged PRs in 90 days, which include dependency automation. Four commit authors were active in the past year, and one account handled every merge attributed to non-bot accounts, so these counts do not establish a broad contributor base.

When to choose: Choose Dekaf when your brokers run Kafka 4.0+ and you want to avoid a native Kafka library or use async streams. Weigh its short release history and concentrated maintenance.

KNet: the Java client through a JVM bridge

KNet (MASES.KNet 3.3.0) takes a different approach: it runs Apache Kafka's Java libraries inside the .NET process through the JCOBridge runtime. That gives .NET code the Java producer, consumer, admin, Streams, and Connect APIs.

The trade-off is a Java 17+ runtime and separate runtime licensing. KNet itself is Apache-2.0 licensed, but its JCOBridge 2.6 runtime requires a commercial license when its use generates direct or indirect income. Consider KNet when you need Kafka Streams' Java APIs or want to write Kafka Connect connectors in .NET, and can accept the JVM dependency and licensing terms.

Kafka .NET frameworks compared

Capabilities verified against each release's documentation and packages: 9 Oct 2026

AreaKafkaFlow 4.2.0MassTransit 9.2.3Wolverine 6.48.2Silverback 5.5.2CAP 10.0.2
ScopeKafka onlyMessage bus; Kafka runs as a rider beside a bus transportMessaging and command handling over many transportsKafka and MQTTOutbox-based event bus over seven transports
Concurrency and orderingWorkers per consumer; same partition key to the same worker by defaultConfigurable concurrency across keys; per-key order by defaultUp to MaxDegreeOfParallelism; ProcessConcurrentlyByKey keeps per-key orderParallel across partitions; sequential within each partition by defaultOne consumer thread by default; parallel execution and retries can reorder messages
Failed messagesLogged and skipped by default; retries through KafkaFlow.RetryFaulted messages discarded by default; configurable retries, delay-topic redelivery, and error topicsRetry policies; opt-in retry topics and Kafka dead-letter topicsStops the consumer by default; configurable retry, skip, and move policiesImmediate retries, then storage-based retries; default retry limit 50
OutboxCommunity package Contrib.KafkaFlow.OutboxEF Core or MongoDB transactional outbox on topic endpointsDurable inbox and outboxTransactional outboxCore feature
Schema RegistryAvro, Protobuf, and JSON Schema serializer packagesConfluent serializers configured on the riderAvro and JSON Schema serializers built inAvro, Protobuf, and JSON Schema through Silverback.Integration.Kafka.SchemaRegistryNot built in
LicenseMITCommercial (v9); Apache-2.0 (v8)MITMITMIT
Target frameworks.NET Standard 2.0.NET Framework 4.7.2, .NET Standard 2.0, .NET 8–10.NET 9, .NET 10.NET 10.NET 8

All five frameworks use Confluent.Kafka and depend on librdkafka; native platform support depends on the Confluent.Kafka version resolved by your application. Unless overridden, their producers use CRC32 partitioning for non-empty serialized keys. Matching partition placement requires identical key bytes and partition counts.

KafkaFlow

KafkaFlow is a Kafka-only framework from Farfetch.

  • Processing model: Each consumer runs a configurable number of workers with a buffer each. The default BytesSum distribution keeps messages with the same partition key in order; FreeWorker is faster but loses that order.
  • Failure handling: By default, a handler exception is logged and the message still counts as processed. KafkaFlow.Retry adds simple, forever, and durable retries, with durable retries stored in SQL Server, PostgreSQL, or MongoDB.
  • Typed handlers: With the default type resolver, the producer writes a Message-Type header containing the .NET type and assembly name. For producers without this header, use a single-type deserializer when the topic carries one message type, or configure a custom type resolver.
  • Operations: Optional admin packages provide a web API and dashboard to pause or resume consumers, reset or rewind offsets, and change worker counts. Commands targeting a consumer or group affect all application instances.
  • Maintenance: The repository snapshot shows the last default-branch commit on 8 May 2026 and 24 PRs opened but none merged in 90 days. The latest release is 4.2.0 (11 Mar 2026).

When to choose: Choose KafkaFlow for Kafka-only consumers that need parallel processing with per-key ordering and middleware, and add retry handling from the start. Watch the maintenance trend before committing a new system to it.

MassTransit

MassTransit is a general message bus. Kafka support comes as a rider: you configure a bus transport, which can be in-memory, and add Kafka topic endpoints beside it. Producing to Kafka goes through the rider-specific ITopicProducer<T> interface, not the bus's Publish API.

  • Processing model: Partitions are processed independently, with one message at a time per partition by default. Raise ConcurrentMessageLimit to process different keys concurrently within a partition; keep ConcurrentDeliveryLimit at 1 to preserve per-key ordering.
  • Offsets: MassTransit checkpoints successfully consumed records per partition, by default every minute or every 5,000 messages. Its documentation warns that a forced shutdown can cause duplicate consumption.
  • Reliability: Faulted messages are discarded by default. Version 9.2+ supports an opt-in error topic (EnableErrorTopic) and delayed redelivery through companion delay topics (UseKafkaDelayedRedelivery). Delayed redelivery automatically enables the error topic for messages that exhaust redelivery, but later records may be processed first. Version 9.1+ supports the Entity Framework Core or MongoDB transactional outbox on topic endpoints. Sagas can also run on topic endpoints.
  • Headers: The rider writes MassTransit headers such as MessageId, CorrelationId, and Content-Type when they have values. Consumers in other languages see these as ordinary record headers.

Licensing. Since v9.0.0 (6 Jan 2026), MassTransit is commercially licensed by Massient and needs a license key at runtime, set through MT_LICENSE or in code. Organizations with gross annual revenue under USD 1 million may qualify for a 100% discount, without commercial support, and the v9 source is available only to licensed customers and community users with GitHub access. Version 8 remains Apache-2.0, with security patches announced through 2026. OpenTransit, a community fork of v8 targeting .NET 10+, plans to publish packages after that but had published none as of 9 Oct 2026.

When to choose: Choose MassTransit when Kafka needs to join an existing MassTransit application, or when you want its consumer middleware and saga model. For a new Kafka-only service, weigh the rider configuration and v9 licensing requirements against KafkaFlow or plain Confluent.Kafka. If you stay on v8, plan for its end of support.

Wolverine

Wolverine is a messaging and command-handling framework from JasperFx. Its Kafka transport focuses on keeping database changes and messages consistent.

  • Durable inbox and outbox: UseDurableInbox() persists incoming messages for recovery. With message storage, durable outgoing endpoints, and transactional middleware or an outbox publishing service configured, database changes and outgoing messages are stored in the same transaction. The outbox forwards messages to Kafka after commit. Message storage supports PostgreSQL, SQL Server, MySQL, SQLite, Oracle, and RavenDB, with integrations for Marten and EF Core.
  • Offset commits: By default, StoreThenAutoFlush disables automatic offset storage and flushes stored offsets in the background. Buffered listeners advance only past completed records, even under concurrency. Durable listeners make records committable once they are persisted to the inbox, without waiting for handler completion.
  • Failure handling: Standard Wolverine retry policies apply. For database-backed applications, prefer scheduled retries through durable storage. Non-blocking Kafka retry topics are an opt-in alternative that can reorder processing. Enable a Kafka dead-letter topic per listener with EnableNativeDeadLetterQueue().

When to choose: Choose Wolverine when database updates must reliably produce Kafka events, especially if the application already uses Marten or EF Core. Wolverine 6.48.2 targets .NET 9 and .NET 10.

Silverback and CAP

Silverback is a message bus for Kafka and MQTT, with a transactional outbox, configurable error policies, and Schema Registry integration. Consider it when you need a common API for both brokers, batch consumption, or automatic splitting and reassembly of large messages. Silverback 5.5.2 targets .NET 10, following the project's latest-LTS policy.

CAP is built around the outbox pattern. It stores published and received messages in SQL Server, MySQL, PostgreSQL, or MongoDB, retries failures from that storage, and shows message status in a dashboard. Kafka is one of seven supported transports. Delivery is at least once; subscribers must handle duplicate messages. Kafka records use JSON payloads by default and CAP metadata headers. When consuming from non-CAP producers, CustomHeadersBuilder can supply metadata needed by CAP subscribers.

Other frameworks: Brighter and SlimMessageBus

  • Brighter is a command dispatcher and processor with a Kafka gateway, Paramore.Brighter.MessagingGateway.Kafka. Consider it when you want a command-handler middleware pipeline for both in-process and Kafka-delivered messages.
  • SlimMessageBus is a lightweight bus for publish-subscribe and request-response, with a Kafka provider, SlimMessageBus.Host.Kafka. Consider it when you want a lightweight messaging API with pluggable transports and optional outbox support.

Both use Confluent.Kafka underneath.

Stream processing in .NET

Apache Kafka Streams is a Java library, and there is no official .NET version. Two community libraries cover different needs, and they are not interchangeable.

Stateful processing: aggregations, joins, and windows. Streamiz.Kafka.Net 1.8.2 (24 Sep 2026) offers a Kafka Streams-style DSL and Processor API on Confluent.Kafka. It supports in-memory and RocksDB state stores, KStream and KTable joins, and hopping and tumbling windows. It defaults to at-least-once processing; set Guarantee to ProcessingGuarantee.EXACTLY_ONCE for exactly-once Kafka-to-Kafka processing. External database writes and API calls are outside that guarantee. Its README lists standby replicas and sliding and session windows as "No plan for now."

Consumer pipelines with backpressure. Akka.Streams.Kafka 1.5.67 (28 Apr 2026) is a port of Alpakka Kafka on Confluent.Kafka. It consumes records on demand as downstream stages are ready. Its committable sources expose offsets that the application passes to Committer after successful processing, allowing commits to be batched. It does not provide Kafka Streams-style state stores, and its README says transactional producers and consumers are "not implemented yet."

If you need the Java Kafka Streams API itself, KNet lets .NET code call Apache's Java library through a JVM hosted in the same process.

GitHub repository metrics

The main tables cover the four libraries named in this guide's title and description. A shorter table covers Wolverine, CAP, Silverback, and Streamiz. Snapshot: 9 Oct 2026.

The public MassTransit repository holds the v8 line; v9 is developed outside it, so these figures say nothing about v9 maintenance. MassTransit's figures also cover every transport, not only the Kafka rider.

Project overview

Confluent.KafkaKafkaFlowMassTransit v8Dekaf
Repository created1 Nov 20162 Jun 202016 Jul 201021 Jan 2026
LicenseApache-2.0MITApache-2.0MIT

Activity

MetricConfluent.KafkaKafkaFlowMassTransit v8Dekaf
Latest default-branch commit7 Oct 20268 May 202627 Sep 20269 Oct 2026
Latest GitHub Releasev2.16.0 (7 Oct 2026)4.2.0 (11 Mar 2026)—v1.23.3 (9 Oct 2026)
GitHub Releases (12 mo)92039
Commits22 (90 d) · 85 (12 mo)0 (90 d) · 34 (12 mo)3 (90 d) · 38 (12 mo)1,295 (90 d) · 3,924 (12 mo)
Issue flow (90 d)2 opened · 3 closed4 opened · 0 closed7 opened · 7 closed566 opened · 559 closed
PR flow (90 d)26 opened · 22 merged24 opened · 0 merged5 opened · 0 merged1,238 opened · 1,197 merged
Activity assessment🟢 22 commits and 22 merged PRs in the last 90 days.🔴 No commits and no merged PRs in the last 90 days.🟡 3 commits and 0 merged PRs in the last 90 days.🟢 1,295 commits and 1,197 merged PRs in the last 90 days.

Activity counts include automation; commit counts cover the default branch. Release figures count GitHub Releases only: MassTransit publishes v8 versions to NuGet without GitHub Releases, most recently 8.5.11 on 30 Sep 2026.

Maintenance

MetricConfluent.KafkaKafkaFlowMassTransit v8Dekaf
Active commit authors (12 mo)23654
PR merge distribution (12 mo)14 accounts · Top 1: 51% · Top 2: 64%2 accounts · Top 1: 84% · Top 2: 100%1 account · 100% of non-bot merges1 account · 100% of non-bot merges
Issue backlog381 open · median age 5.5 y59 open · median age 2.3 y1 open · median age 115 d9 open · median age 41 d
PR backlog92 open · median age 2.9 y67 open · median age 143 d1 open · median age 6 d1 open · median age 3 d
Median PR merge time (90 d)5.4 d (n=22)N/A — no merged PRs in windowN/A — no merged PRs in window<1 h (n=1,197)
Responsiveness assessment🟡 For the 22 PRs merged in the last 90 d, the median creation-to-merge time was 5.4 d, but 92 open PRs have a median age of 2.9 y.🟡 Median open PR age 143 d exceeds 60 d.🟢 The median open PR age is 6 d; 10 of 11 issues closed within 90 d.🟢 For the 1,197 PRs merged in the last 90 d, the median creation-to-merge time was <1 h; the median open PR age is 3 d, and 340 of 341 issues closed within 90 d.

PR merge distribution counts non-bot mergedBy accounts; it does not measure reviewer or maintainer headcount. Median PR merge time measures creation to merge for PRs merged in the last 90 days; unmerged PRs are excluded, and automated PRs are included. Issue closure figures use issues opened 90–180 days before the snapshot; they measure closure, not first-response time. None of the four repositories has a published GitHub security advisory.

Public usage and interest

MetricConfluent.KafkaKafkaFlowMassTransit v8Dekaf
Stars2787827,80388
Forks9001471,9725
GitHub dependents (Used by)11,98817613,4036

Stars and forks reflect public interest; GitHub reports only 278 stars for Confluent.Kafka, far fewer than its forks and dependents would suggest. GitHub dependents approximate visible public repository usage and do not capture private deployments.

MetricWolverineCAPSilverbackStreamiz
Latest default-branch commit9 Oct 20267 Oct 202626 Sep 202623 Sep 2026
Latest GitHub ReleaseV6.48.2 (9 Oct 2026)v10.0.2 (1 Aug 2026)v5.5.2 (10 Sep 2026)v1.8.2 (24 Sep 2026)
GitHub Releases (12 mo)1454164
Commits1,352 (90 d) · 3,453 (12 mo)5 (90 d) · 39 (12 mo)55 (90 d) · 146 (12 mo)19 (90 d) · 88 (12 mo)
PR flow (90 d)869 opened · 834 merged6 opened · 0 merged2 opened · 1 merged5 opened · 5 merged
Stars2,3787,112285545

Wolverine, CAP, and Silverback figures cover their other transports as well as Kafka.

NuGet downloads

PackageLibraryTotal downloads
Confluent.KafkaConfluent.Kafka277.4M
MassTransit.KafkaMassTransit14.6M
KafkaFlowKafkaFlow12.6M
MASES.KNetKNet3.0M
DotNetCore.CAP.KafkaCAP2.8M
Silverback.Integration.KafkaSilverback1.5M
Streamiz.Kafka.NetStreamiz1.2M
Akka.Streams.KafkaAkka.Streams.Kafka938.7K
WolverineFx.KafkaWolverine594.9K
SlimMessageBus.Host.KafkaSlimMessageBus518.8K
Paramore.Brighter.MessagingGateway.KafkaBrighter198.0K
DekafDekaf96.0K

KNet, Akka.Streams.Kafka, Brighter, and SlimMessageBus are supplementary options outside the Quick decision table, so they appear here only with NuGet downloads. Downloads include CI builds and transitive dependencies, not unique users. The framework and stream-processing packages in this table depend on Confluent.Kafka, so its total includes downloads through them.

Overall repository signals

  • Confluent.Kafka leads NuGet downloads by a wide margin and had 23 active commit authors and 14 non-bot accounts merging PRs in the past year. Its 381 open issues have a median age of 5.5 years.
  • KafkaFlow has 12.6M downloads and 176 GitHub dependents, but no commits or merged PRs in the last 90 days, with 67 PRs still open.
  • MassTransit v8 had 3 commits and no merged PRs in the last 90 days, but closed 10 of 11 issues in the measured cohort within 30 days and shipped 8.5.11 to NuGet in September 2026. That pattern fits a version in maintenance mode.
  • Dekaf is by far the most active of the four, with 1,295 commits in the last 90 days and 39 GitHub releases in the past year, and its 1,197 merged PRs had a median merge time under an hour. It is also the youngest project, has 96.0K NuGet downloads, and one account handled 100% of merges attributed to non-bot accounts in the past year.
  • Among the other options, Wolverine is the most active, with 834 merged PRs in the last 90 days and 145 GitHub releases in the past year. Streamiz merged 5 PRs in the last 90 days. CAP had no merged PRs in 90 days but shipped 4 releases in the past year.

These are maintenance and adoption signals, not evidence of runtime quality or feature fit.

Test .NET Kafka clients with Kafma

Before you pick a library or switch producers, check four things on a test cluster: failure handling, framework headers, commit timing, and partition placement.

Kafma is a desktop Kafka GUI that runs next to your .NET service. In its Kafka console, you can send test records, inspect what a producer wrote, and watch a consumer group's committed offsets.

Kafma console with topic tabs, a live message stream, and a producer with partition, headers, and Loop controls

Test handler failures

From the producer panel, send three records to one partition: a valid record, one that deserializes but makes your handler throw, and another valid record. Then check in Watch Group whether the committed offset moves past the failing record. With default settings:

  • Confluent.Kafka and KafkaFlow can commit it even though the handler failed.
  • Dekaf can commit it if your loop catches the exception and continues.
  • MassTransit discards it; in v9.2+, an error topic is opt-in.
  • Silverback stops the consumer, so the offset does not move past it.
  • Wolverine retries first, and a Kafka dead-letter topic is opt-in. With a durable inbox, the offset can be committed once the message is persisted.

An offset past the record only means the consumer moved on; check your logs, error or dead-letter topics, and database to see what happened. Test decoding errors separately, on a topic without a schema bound by topic name, because Kafma validates records against that schema. For tombstones, use a non-null key and set the value type to Null.

Check framework headers

Open a record the framework wrote to see its headers. MassTransit adds MessageId and Content-Type, KafkaFlow's default type resolver adds Message-Type, and CAP adds its own metadata headers.

To find which headers your consumer needs, replay the record to the same topic, which keeps its partition but encodes the key and value again. Send it unchanged first and check that its Raw bytes match the original, then replay it again with one header removed. With Confluent's schema-ID prefix, matching bytes also confirm the schema ID: 00 followed by four ID bytes.

Kafma message details showing record headers, an Avro schema ID, and the Decoded and Raw views

Check commits and restarts

Use Loop to keep records arriving and watch the committed offsets in Watch Group. By default, Confluent.Kafka commits every 5 seconds, and MassTransit checkpoints after one minute or 5,000 messages.

Next, stop the service gracefully and then force-terminate it, restarting it each time. Watch Group shows where each partition's commits stopped; compare that with your logs to find records processed more than once. Kafma reads this state without joining the group or committing offsets, and its consumer group UI shows lag by topic, partition, and member.

Kafma watching pending and consumed records around a consumer group's committed offsets

Compare partitions across producers

Confluent.Kafka and the frameworks in this guide hash non-empty keys with CRC32 by default; Dekaf and the Java client use Murmur2. Kafma's producer uses Java-compatible Murmur2 when Partition is set to Auto, so it can stand in for a Java producer. Send the same non-empty keys from Kafma, with the key type set to String, and from your .NET producer as plain UTF-8 strings to one test topic, leaving partition selection automatic on both sides. Then compare each key's partition in the console.

When sharing a topic with Java producers, set Partitioner = Partitioner.Murmur2Random in Confluent.Kafka to align keyed partitioning.

Download Kafma and connect it to the same test cluster as your .NET service.

Frequently asked questions

Is there an official Apache Kafka client for .NET?

No. Apache Kafka's first-party client is Java. Confluent.Kafka is Confluent's official .NET client, built on librdkafka. Dekaf is an independent pure C# implementation, and KNet runs the Java client through a JVM bridge.

How do I fix "Failed to load the librdkafka native library"?

Check that your platform is one librdkafka.redist ships: linux-x64, linux-arm64, linux-s390x, osx-x64, osx-arm64, win-x64, or win-x86, with Alpine builds for Linux x64 and ARM64. Make sure the published output contains the native library for your process architecture and, on Linux, the matching glibc or musl build, along with its dependencies. On other platforms, install librdkafka yourself and call Library.Load with its path before creating a client, or use Dekaf, which has no native library.

Does Confluent.Kafka support async consume?

No. Consume blocks until a record arrives or the cancellation token fires, so run the loop on a dedicated thread or in a hosted worker that does not block application startup. Producing is async through ProduceAsync. Dekaf provides an async ConsumeAsync that returns IAsyncEnumerable.

Which .NET Kafka clients support KIP-848?

Confluent.Kafka 2.12.0 and later, with GroupProtocol = GroupProtocol.Consumer on Kafka 4.0+; the default is still the classic protocol. Dekaf implements only the consumer protocol and documents Kafka 4.0 or later as the baseline for its consumer groups. For frameworks, check the resolved Confluent.Kafka version and the framework's support for KIP-848 rebalance handling; exposing consumer configuration alone does not establish compatibility.

Do .NET Kafka clients partition keys the same way as Java?

Not all of them. Confluent.Kafka and the frameworks built on it hash non-empty keys with CRC32 by default; set Partitioner = Partitioner.Murmur2Random in Confluent.Kafka, or the same option in each framework's producer configuration, for Java-compatible placement. Dekaf's default Murmur2 matches Java for non-empty keys, but empty keys differ: Dekaf uses sticky partitioning, while Java hashes them. Matching partition placement requires identical serialized key bytes and partition counts.

How do I use Kafka with .NET Aspire?

In the AppHost, use Aspire.Hosting.Kafka with AddKafka, and reference the resource from each service with WithReference. In the service, use Aspire.Confluent.Kafka with AddKafkaProducer or AddKafkaConsumer and the same resource name to get dependency injection, health checks, and telemetry. The application still owns the consumer loop.

Is KafkaFlow still maintained?

The repository is not archived, and 4.2.0 shipped on 11 Mar 2026. However, the 9 Oct 2026 snapshot found no default-branch commits since 8 May 2026 and no merged PRs in the preceding 90 days, with 67 open PRs. Check its activity again before starting a long-lived system on it.

Conclusion

For most .NET services, start with Confluent.Kafka; for consumers, disable automatic offset storage and store offsets only after successful processing. Add KafkaFlow when you need parallel workers with per-key ordering and middleware, but configure retries explicitly and check its maintenance activity first. Consider Dekaf to avoid a native Kafka library, weighing its short release history and the Kafka 4.0+ requirement for its consumer groups.

For an existing MassTransit application, consider the Kafka rider and review v9 licensing requirements. If you stay on v8, plan for the end of its announced security updates. When database updates must reliably produce Kafka events, look at Wolverine or CAP. For stateful stream processing, use Streamiz.Kafka.Net.

This guide is maintained by the team behind Kafma.

Ready to try the Kafka IDE?

Available for macOS, Windows, Linux