[{"data":1,"prerenderedAt":2448},["ShallowReactive",2],{"blog-post-\u002Fblog\u002Fkafka-dotnet-clients":3},{"id":4,"title":5,"body":6,"date":2433,"description":2434,"extension":2435,"meta":2436,"navigation":2437,"ogImage":2438,"ogImageHeight":2438,"ogImageWidth":2438,"path":2439,"pinned":2440,"seo":2441,"sitemap":2442,"stem":2443,"tags":2444,"__hash__":2447},"blog\u002Fblog\u002Fkafka-dotnet-clients.md","Kafka C#\u002F.NET Clients: Confluent.Kafka vs KafkaFlow",{"type":7,"value":8,"toc":2388},"minimark",[9,22,38,41,46,159,162,166,169,172,321,324,328,334,532,535,539,546,551,652,658,661,674,678,741,746,750,762,771,775,779,983,986,989,996,1044,1049,1053,1073,1126,1148,1153,1157,1164,1193,1198,1202,1210,1222,1226,1252,1255,1258,1261,1279,1294,1301,1305,1308,1311,1315,1375,1379,1529,1532,1536,1666,1673,1677,1756,1759,1763,1886,1889,1893,2070,2073,2077,2105,2108,2112,2115,2128,2137,2141,2154,2183,2186,2190,2201,2217,2225,2229,2236,2244,2252,2256,2263,2269,2276,2280,2284,2287,2291,2300,2304,2318,2322,2328,2332,2338,2342,2368,2372,2375,2379,2382,2385],[10,11,12,13,17,18,21],"p",{},"Kafka libraries for C# and .NET fall into two layers. ",[14,15,16],"strong",{},"Clients"," connect to brokers and implement the Kafka protocol; this guide covers Confluent.Kafka and Dekaf. ",[14,19,20],{},"Frameworks"," manage how your application consumes and handles messages. The ones covered here, KafkaFlow, MassTransit, Wolverine, Silverback, and CAP, all build on Confluent.Kafka.",[10,23,24,25,28,29,33,34,37],{},"For most services, start with ",[14,26,27],{},"Confluent.Kafka",", Confluent's client built on the native ",[30,31,32],"code",{},"librdkafka"," library. ",[14,35,36],{},"KafkaFlow"," adds parallel workers, middleware, and consumer lifecycle management. By default, though, it does not retry a message whose handler fails.",[10,39,40],{},"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.",[42,43,45],"h2",{"id":44},"quick-decision","Quick decision",[47,48,49,65],"table",{},[50,51,52],"thead",{},[53,54,55,59,62],"tr",{},[56,57,58],"th",{},"Situation",[56,60,61],{},"Best starting point",[56,63,64],{},"Why",[66,67,68,81,98,116,129,142],"tbody",{},[53,69,70,76,78],{},[71,72,73],"td",{},[14,74,75],{},"Plain producer or consumer in a service or worker",[71,77,27],{},[71,79,80],{},"Confluent'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.",[53,82,83,88,91],{},[71,84,85],{},[14,86,87],{},"No native library in the deployment",[71,89,90],{},"Dekaf",[71,92,93,94,97],{},"Pure C# with async consumption through ",[30,95,96],{},"IAsyncEnumerable",". Consumer groups require Kafka 4.0+, and 1.0.0 shipped in July 2026.",[53,99,100,105,107],{},[71,101,102],{},[14,103,104],{},"Consumers that need parallel workers, middleware, and typed handlers",[71,106,36],{},[71,108,109,110,115],{},"Runs 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 ",[111,112,114],"a",{"href":113},"#github-repository-metrics","maintenance signals",".",[53,117,118,123,126],{},[71,119,120],{},[14,121,122],{},"Existing MassTransit application",[71,124,125],{},"MassTransit Kafka rider",[71,127,128],{},"Adds 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.",[53,130,131,136,139],{},[71,132,133],{},[14,134,135],{},"Database updates must reliably produce Kafka events",[71,137,138],{},"Wolverine or CAP",[71,140,141],{},"A 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.",[53,143,144,149,152],{},[71,145,146],{},[14,147,148],{},"Stateful stream processing: aggregations, joins, windows",[71,150,151],{},"Streamiz.Kafka.Net",[71,153,154,155,115],{},"A Kafka Streams-style library on Confluent.Kafka. See ",[111,156,158],{"href":157},"#stream-processing-in-net","Stream processing in .NET",[10,160,161],{},"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.",[42,163,165],{"id":164},"confluentkafka-vs-kafkaflow-client-or-framework","Confluent.Kafka vs KafkaFlow: client or framework?",[10,167,168],{},"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.",[10,170,171],{},"Here is who handles each concern:",[47,173,174,196],{},[50,175,176],{},[53,177,178,181,189],{},[56,179,180],{},"Concern",[56,182,183],{},[111,184,188],{"href":185,"rel":186},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FConfluent.Kafka\u002F2.16.0",[187],"nofollow","Confluent.Kafka 2.16.0",[56,190,191],{},[111,192,195],{"href":193,"rel":194},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FKafkaFlow\u002F4.2.0",[187],"KafkaFlow 4.2.0",[66,197,198,215,236,252,269,288,309],{},[53,199,200,205,212],{},[71,201,202],{},[14,203,204],{},"Consumer loop",[71,206,207,208,211],{},"Your code calls ",[30,209,210],{},"Consume"," in a loop, usually in a hosted worker.",[71,213,214],{},"KafkaFlow polls and dispatches each message through middleware to your handler.",[53,216,217,222,225],{},[71,218,219],{},[14,220,221],{},"Concurrency",[71,223,224],{},"Your code decides how to process records concurrently, and must preserve per-key order if it dispatches them to several workers.",[71,226,227,228,231,232,235],{},"Several workers per consumer (",[30,229,230],{},"WithWorkersCount","). The default ",[30,233,234],{},"BytesSum"," strategy sends messages with the same partition key to the same worker, preserving their order.",[53,237,238,243,249],{},[71,239,240],{},[14,241,242],{},"Offset commits",[71,244,245,246,248],{},"Auto-commit every 5 s. By default, a record's offset is stored when ",[30,247,210],{}," returns it, before your code runs.",[71,250,251],{},"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.",[53,253,254,259,266],{},[71,255,256],{},[14,257,258],{},"Send retries",[71,260,261,262,265],{},"librdkafka retries retriable send failures until ",[30,263,264],{},"delivery.timeout.ms"," (5 minutes by default) expires. Idempotence is off by default.",[71,267,268],{},"The same: KafkaFlow producers use Confluent.Kafka.",[53,270,271,276,279],{},[71,272,273],{},[14,274,275],{},"Processing retries",[71,277,278],{},"Your code.",[71,280,281,282,287],{},"None by default: the exception is logged, and the message is completed and its offset stored. Add ",[111,283,286],{"href":284,"rel":285},"https:\u002F\u002Fgithub.com\u002FFarfetch\u002Fkafkaflow-retry-extensions",[187],"KafkaFlow.Retry"," for retries.",[53,289,290,295,306],{},[71,291,292],{},[14,293,294],{},"Serialization",[71,296,297,298,301,302,305],{},"Built-in serializers for common types, custom ",[30,299,300],{},"ISerializer"," and ",[30,303,304],{},"IDeserializer"," implementations, or Confluent's Schema Registry serdes.",[71,307,308],{},"Serializer middleware for JSON, Protobuf, and Schema Registry Avro, Protobuf, and JSON Schema.",[53,310,311,316,318],{},[71,312,313],{},[14,314,315],{},"Lifecycle and operations",[71,317,278],{},[71,319,320],{},"Hosted-service integration, an admin web API, and a dashboard.",[10,322,323],{},"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.",[42,325,327],{"id":326},"kafka-net-clients-compared","Kafka .NET clients compared",[10,329,330,333],{},[14,331,332],{},"Capabilities verified against each release's documentation and packages:"," 9 Oct 2026",[47,335,336,355],{},[50,337,338],{},[53,339,340,343,348],{},[56,341,342],{},"Area",[56,344,345],{},[111,346,188],{"href":185,"rel":347},[187],[56,349,350],{},[111,351,354],{"href":352,"rel":353},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FDekaf\u002F1.23.3",[187],"Dekaf 1.23.3",[66,356,357,374,387,400,421,437,453,465,482,499,519],{},[53,358,359,364,371],{},[71,360,361],{},[14,362,363],{},"Implementation",[71,365,366,367,370],{},"Wraps librdkafka 2.16.0 from the ",[30,368,369],{},"librdkafka.redist"," package",[71,372,373],{},"Pure C#",[53,375,376,381,384],{},[71,377,378],{},[14,379,380],{},"Target frameworks",[71,382,383],{},".NET Framework 4.6.2, .NET Standard 2.0, .NET 8, .NET 10",[71,385,386],{},".NET Standard 2.0, .NET 8, .NET 10",[53,388,389,394,397],{},[71,390,391],{},[14,392,393],{},"Native binaries",[71,395,396],{},"linux-x64 and linux-arm64 (glibc and Alpine musl), linux-s390x, osx-x64, osx-arm64, win-x64, win-x86",[71,398,399],{},"None; Native AOT tested on .NET 10 linux-x64",[53,401,402,407,413],{},[71,403,404],{},[14,405,406],{},"Consume API",[71,408,409,410],{},"Blocking ",[30,411,412],{},"Consume(CancellationToken)",[71,414,415,418,419],{},[30,416,417],{},"ConsumeAsync"," returning ",[30,420,96],{},[53,422,423,428,434],{},[71,424,425],{},[14,426,427],{},"Consumer groups",[71,429,430,431],{},"Classic, including cooperative-sticky; KIP-848 with ",[30,432,433],{},"GroupProtocol.Consumer",[71,435,436],{},"KIP-848 only; requires Kafka 4.0+",[53,438,439,444,450],{},[71,440,441],{},[14,442,443],{},"Default offset commits",[71,445,446,447,449],{},"Automatic every 5 s; offsets stored as soon as ",[30,448,210],{}," returns a record",[71,451,452],{},"Automatic every 5 s; a record becomes eligible for commit when a sequential consume loop requests the next record",[53,454,455,460,463],{},[71,456,457],{},[14,458,459],{},"Transactions",[71,461,462],{},"Yes",[71,464,462],{},[53,466,467,472,479],{},[71,468,469],{},[14,470,471],{},"Security",[71,473,474,475,478],{},"TLS\u002FmTLS; SASL PLAIN, SCRAM, GSSAPI (platform-dependent), OAUTHBEARER with built-in OIDC; AWS MSK IAM through ",[30,476,477],{},"AWS.MSK.Auth"," tokens",[71,480,481],{},"TLS\u002FmTLS; SASL PLAIN, SCRAM, GSSAPI (.NET 8 and 10), OAUTHBEARER; AWS MSK IAM",[53,483,484,489,496],{},[71,485,486],{},[14,487,488],{},"Default partitioner for non-empty keys",[71,490,491,492,495],{},"CRC32 (",[30,493,494],{},"consistent_random",")",[71,497,498],{},"Murmur2, Java-compatible",[53,500,501,506,513],{},[71,502,503],{},[14,504,505],{},"Schema Registry",[71,507,508,509,512],{},"Avro, Protobuf, and JSON Schema via separate ",[30,510,511],{},"Confluent.SchemaRegistry.Serdes.*"," packages",[71,514,515,516],{},"Avro, Protobuf, and JSON Schema; payload validation for JSON Schema requires optional ",[30,517,518],{},"Dekaf.SchemaRegistry.Json",[53,520,521,526,529],{},[71,522,523],{},[14,524,525],{},"License",[71,527,528],{},"Apache-2.0",[71,530,531],{},"MIT",[10,533,534],{},"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.",[536,537,27],"h3",{"id":538},"confluentkafka",[10,540,541,545],{},[111,542,27],{"href":543,"rel":544},"https:\u002F\u002Fgithub.com\u002Fconfluentinc\u002Fconfluent-kafka-dotnet",[187]," 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.",[10,547,548],{},[14,549,550],{},"Capabilities and limitations",[552,553,554,576,587,601,615,627,642],"ul",{},[555,556,557,560,561,564,565,568,569,572,573,575],"li",{},[14,558,559],{},"API:"," ",[30,562,563],{},"ProduceAsync"," returns a delivery result; to reduce per-message ",[30,566,567],{},"Task"," overhead, ",[30,570,571],{},"Produce"," takes a delivery callback instead. ",[30,574,210],{}," is blocking, so run the loop on a dedicated thread or in a hosted worker that does not block application startup.",[555,577,578,560,581,583,584,115],{},[14,579,580],{},"Native library:",[30,582,369],{}," 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 ",[30,585,586],{},"Library.Load",[555,588,589,592,593,596,597,600],{},[14,590,591],{},"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 ",[30,594,595],{},"EnableAutoOffsetStore = false",", and call ",[30,598,599],{},"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.",[555,602,603,606,607,610,611,614],{},[14,604,605],{},"Consumer groups:"," With the classic protocol, set ",[30,608,609],{},"PartitionAssignmentStrategy = PartitionAssignmentStrategy.CooperativeSticky"," for incremental rebalances. KIP-848 has been production-ready since Confluent.Kafka 2.12.0; enable it with ",[30,612,613],{},"GroupProtocol = GroupProtocol.Consumer"," on Kafka 4.0+. Under this protocol, partition assignment is controlled by the broker.",[555,616,617,560,620,622,623,626],{},[14,618,619],{},"Default partitioner:",[30,621,494],{}," hashes keys with CRC32. Set ",[30,624,625],{},"Partitioner = Partitioner.Murmur2Random"," for Java-compatible key-to-partition mapping. The frameworks below inherit this default unless you change the producer configuration.",[555,628,629,632,633,636,637,641],{},[14,630,631],{},"Authentication:"," OAUTHBEARER supports OIDC directly with ",[30,634,635],{},"SaslOauthbearerMethod.Oidc",". For AWS MSK IAM, use AWS's ",[111,638,477],{"href":639,"rel":640},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FAWS.MSK.Auth",[187]," token generator with an OAUTHBEARER refresh handler.",[555,643,644,647,648,651],{},[14,645,646],{},"Maintenance:"," The ",[111,649,650],{"href":113},"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.",[10,653,654,657],{},[14,655,656],{},"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.",[536,659,90],{"id":660},"dekaf",[10,662,663,667,668,673],{},[111,664,90],{"href":665,"rel":666},"https:\u002F\u002Fgithub.com\u002Fthomhurst\u002FDekaf",[187]," 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 ",[111,669,672],{"href":670,"rel":671},"https:\u002F\u002Fthomhurst.github.io\u002FDekaf\u002Fdocs\u002Fkafka-feature-support",[187],"feature support matrix","; test it against your brokers.",[10,675,676],{},[14,677,550],{},[552,679,680,695,700,712,721,727,733],{},[555,681,682,684,685,688,689,691,692,694],{},[14,683,559],{}," Producers and consumers are created with fluent builders such as ",[30,686,687],{},"Kafka.CreateProducer\u003CTKey, TValue>()",". ",[30,690,417],{}," returns a long-lived ",[30,693,96],{},", and LINQ-style extensions filter and batch records.",[555,696,697,699],{},[14,698,605],{}," 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.",[555,701,702,704,705,708,709,711],{},[14,703,591],{}," 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 ",[30,706,707],{},"WithAutoOffsetStore(false)"," and call ",[30,710,599],{}," after successful processing. Retry or durably route failed records before advancing the stored offset past them in the same partition.",[555,713,714,716,717,720],{},[14,715,619],{}," Non-empty serialized keys use Java-compatible Murmur2 hashing; null or empty keys use uniform sticky partitioning. ",[30,718,719],{},"ConsistentRandom"," provides Confluent.Kafka-compatible CRC32 mapping for non-empty keys, given identical key bytes and partition counts.",[555,722,723,726],{},[14,724,725],{},"Compression:"," Gzip is built in. LZ4, Zstd, and Snappy come as separate packages, implemented in C# and registered explicitly by both producers and consumers.",[555,728,729,732],{},[14,730,731],{},"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.",[555,734,735,737,738,740],{},[14,736,646],{}," 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 ",[111,739,650],{"href":113}," 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.",[10,742,743,745],{},[14,744,656],{}," 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.",[536,747,749],{"id":748},"knet-the-java-client-through-a-jvm-bridge","KNet: the Java client through a JVM bridge",[10,751,752,757,758,761],{},[111,753,756],{"href":754,"rel":755},"https:\u002F\u002Fgithub.com\u002Fmasesgroup\u002FKNet",[187],"KNet"," (",[30,759,760],{},"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.",[10,763,764,765,770],{},"The trade-off is a Java 17+ runtime and separate runtime licensing. KNet itself is Apache-2.0 licensed, but its ",[111,766,769],{"href":767,"rel":768},"https:\u002F\u002Fwww.jcobridge.com\u002Fpricing-26\u002F",[187],"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.",[42,772,774],{"id":773},"kafka-net-frameworks-compared","Kafka .NET frameworks compared",[10,776,777,333],{},[14,778,332],{},[47,780,781,820],{},[50,782,783],{},[53,784,785,787,792,799,806,813],{},[56,786,342],{},[56,788,789],{},[111,790,195],{"href":193,"rel":791},[187],[56,793,794],{},[111,795,798],{"href":796,"rel":797},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FMassTransit.Kafka\u002F9.2.3",[187],"MassTransit 9.2.3",[56,800,801],{},[111,802,805],{"href":803,"rel":804},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FWolverineFx.Kafka\u002F6.48.2",[187],"Wolverine 6.48.2",[56,807,808],{},[111,809,812],{"href":810,"rel":811},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FSilverback.Integration.Kafka\u002F5.5.2",[187],"Silverback 5.5.2",[56,814,815],{},[111,816,819],{"href":817,"rel":818},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FDotNetCore.CAP.Kafka\u002F10.0.2",[187],"CAP 10.0.2",[66,821,822,844,874,896,921,945,962],{},[53,823,824,829,832,835,838,841],{},[71,825,826],{},[14,827,828],{},"Scope",[71,830,831],{},"Kafka only",[71,833,834],{},"Message bus; Kafka runs as a rider beside a bus transport",[71,836,837],{},"Messaging and command handling over many transports",[71,839,840],{},"Kafka and MQTT",[71,842,843],{},"Outbox-based event bus over seven transports",[53,845,846,851,854,857,868,871],{},[71,847,848],{},[14,849,850],{},"Concurrency and ordering",[71,852,853],{},"Workers per consumer; same partition key to the same worker by default",[71,855,856],{},"Configurable concurrency across keys; per-key order by default",[71,858,859,860,863,864,867],{},"Up to ",[30,861,862],{},"MaxDegreeOfParallelism","; ",[30,865,866],{},"ProcessConcurrentlyByKey"," keeps per-key order",[71,869,870],{},"Parallel across partitions; sequential within each partition by default",[71,872,873],{},"One consumer thread by default; parallel execution and retries can reorder messages",[53,875,876,881,884,887,890,893],{},[71,877,878],{},[14,879,880],{},"Failed messages",[71,882,883],{},"Logged and skipped by default; retries through KafkaFlow.Retry",[71,885,886],{},"Faulted messages discarded by default; configurable retries, delay-topic redelivery, and error topics",[71,888,889],{},"Retry policies; opt-in retry topics and Kafka dead-letter topics",[71,891,892],{},"Stops the consumer by default; configurable retry, skip, and move policies",[71,894,895],{},"Immediate retries, then storage-based retries; default retry limit 50",[53,897,898,903,909,912,915,918],{},[71,899,900],{},[14,901,902],{},"Outbox",[71,904,905,906],{},"Community package ",[30,907,908],{},"Contrib.KafkaFlow.Outbox",[71,910,911],{},"EF Core or MongoDB transactional outbox on topic endpoints",[71,913,914],{},"Durable inbox and outbox",[71,916,917],{},"Transactional outbox",[71,919,920],{},"Core feature",[53,922,923,927,930,933,936,942],{},[71,924,925],{},[14,926,505],{},[71,928,929],{},"Avro, Protobuf, and JSON Schema serializer packages",[71,931,932],{},"Confluent serializers configured on the rider",[71,934,935],{},"Avro and JSON Schema serializers built in",[71,937,938,939],{},"Avro, Protobuf, and JSON Schema through ",[30,940,941],{},"Silverback.Integration.Kafka.SchemaRegistry",[71,943,944],{},"Not built in",[53,946,947,951,953,956,958,960],{},[71,948,949],{},[14,950,525],{},[71,952,531],{},[71,954,955],{},"Commercial (v9); Apache-2.0 (v8)",[71,957,531],{},[71,959,531],{},[71,961,531],{},[53,963,964,968,971,974,977,980],{},[71,965,966],{},[14,967,380],{},[71,969,970],{},".NET Standard 2.0",[71,972,973],{},".NET Framework 4.7.2, .NET Standard 2.0, .NET 8–10",[71,975,976],{},".NET 9, .NET 10",[71,978,979],{},".NET 10",[71,981,982],{},".NET 8",[10,984,985],{},"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.",[536,987,36],{"id":988},"kafkaflow",[10,990,991,995],{},[111,992,36],{"href":993,"rel":994},"https:\u002F\u002Fgithub.com\u002FFarfetch\u002Fkafkaflow",[187]," is a Kafka-only framework from Farfetch.",[552,997,998,1011,1021,1031,1037],{},[555,999,1000,1003,1004,1006,1007,1010],{},[14,1001,1002],{},"Processing model:"," Each consumer runs a configurable number of workers with a buffer each. The default ",[30,1005,234],{}," distribution keeps messages with the same partition key in order; ",[30,1008,1009],{},"FreeWorker"," is faster but loses that order.",[555,1012,1013,1016,1017,1020],{},[14,1014,1015],{},"Failure handling:"," By default, a handler exception is logged and the message still counts as processed. ",[111,1018,286],{"href":284,"rel":1019},[187]," adds simple, forever, and durable retries, with durable retries stored in SQL Server, PostgreSQL, or MongoDB.",[555,1022,1023,1026,1027,1030],{},[14,1024,1025],{},"Typed handlers:"," With the default type resolver, the producer writes a ",[30,1028,1029],{},"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.",[555,1032,1033,1036],{},[14,1034,1035],{},"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.",[555,1038,1039,647,1041,1043],{},[14,1040,646],{},[111,1042,650],{"href":113}," 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).",[10,1045,1046,1048],{},[14,1047,656],{}," 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.",[536,1050,1052],{"id":1051},"masstransit","MassTransit",[10,1054,1055,1059,1060,1064,1065,1068,1069,1072],{},[111,1056,1052],{"href":1057,"rel":1058},"https:\u002F\u002Fgithub.com\u002FMassTransit\u002FMassTransit",[187]," is a general message bus. Kafka support comes as a ",[1061,1062,1063],"em",{},"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 ",[30,1066,1067],{},"ITopicProducer\u003CT>"," interface, not the bus's ",[30,1070,1071],{},"Publish"," API.",[552,1074,1075,1088,1094,1108],{},[555,1076,1077,1079,1080,1083,1084,1087],{},[14,1078,1002],{}," Partitions are processed independently, with one message at a time per partition by default. Raise ",[30,1081,1082],{},"ConcurrentMessageLimit"," to process different keys concurrently within a partition; keep ",[30,1085,1086],{},"ConcurrentDeliveryLimit"," at 1 to preserve per-key ordering.",[555,1089,1090,1093],{},[14,1091,1092],{},"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.",[555,1095,1096,1099,1100,1103,1104,1107],{},[14,1097,1098],{},"Reliability:"," Faulted messages are discarded by default. Version 9.2+ supports an opt-in error topic (",[30,1101,1102],{},"EnableErrorTopic",") and delayed redelivery through companion delay topics (",[30,1105,1106],{},"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.",[555,1109,1110,1113,1114,1117,1118,1121,1122,1125],{},[14,1111,1112],{},"Headers:"," The rider writes MassTransit headers such as ",[30,1115,1116],{},"MessageId",", ",[30,1119,1120],{},"CorrelationId",", and ",[30,1123,1124],{},"Content-Type"," when they have values. Consumers in other languages see these as ordinary record headers.",[10,1127,1128,1131,1132,1135,1136,1141,1142,1147],{},[14,1129,1130],{},"Licensing."," Since v9.0.0 (6 Jan 2026), MassTransit is commercially licensed by Massient and needs a license key at runtime, set through ",[30,1133,1134],{},"MT_LICENSE"," or in code. Organizations with gross annual revenue under USD 1 million ",[111,1137,1140],{"href":1138,"rel":1139},"https:\u002F\u002Fmassient.com\u002F",[187],"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. ",[111,1143,1146],{"href":1144,"rel":1145},"https:\u002F\u002Fopentransitlab.github.io\u002FOpenTransit\u002F",[187],"OpenTransit",", a community fork of v8 targeting .NET 10+, plans to publish packages after that but had published none as of 9 Oct 2026.",[10,1149,1150,1152],{},[14,1151,656],{}," 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.",[536,1154,1156],{"id":1155},"wolverine","Wolverine",[10,1158,1159,1163],{},[111,1160,1156],{"href":1161,"rel":1162},"https:\u002F\u002Fgithub.com\u002FJasperFx\u002Fwolverine",[187]," is a messaging and command-handling framework from JasperFx. Its Kafka transport focuses on keeping database changes and messages consistent.",[552,1165,1166,1175,1185],{},[555,1167,1168,560,1171,1174],{},[14,1169,1170],{},"Durable inbox and outbox:",[30,1172,1173],{},"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.",[555,1176,1177,1180,1181,1184],{},[14,1178,1179],{},"Offset commits:"," By default, ",[30,1182,1183],{},"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.",[555,1186,1187,1189,1190,115],{},[14,1188,1015],{}," 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 ",[30,1191,1192],{},"EnableNativeDeadLetterQueue()",[10,1194,1195,1197],{},[14,1196,656],{}," 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.",[536,1199,1201],{"id":1200},"silverback-and-cap","Silverback and CAP",[10,1203,1204,1209],{},[111,1205,1208],{"href":1206,"rel":1207},"https:\u002F\u002Fgithub.com\u002FBEagle1984\u002Fsilverback",[187],"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.",[10,1211,1212,1217,1218,1221],{},[111,1213,1216],{"href":1214,"rel":1215},"https:\u002F\u002Fgithub.com\u002Fdotnetcore\u002FCAP",[187],"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, ",[30,1219,1220],{},"CustomHeadersBuilder"," can supply metadata needed by CAP subscribers.",[536,1223,1225],{"id":1224},"other-frameworks-brighter-and-slimmessagebus","Other frameworks: Brighter and SlimMessageBus",[552,1227,1228,1240],{},[555,1229,1230,1235,1236,1239],{},[111,1231,1234],{"href":1232,"rel":1233},"https:\u002F\u002Fgithub.com\u002FBrighterCommand\u002FBrighter",[187],"Brighter"," is a command dispatcher and processor with a Kafka gateway, ",[30,1237,1238],{},"Paramore.Brighter.MessagingGateway.Kafka",". Consider it when you want a command-handler middleware pipeline for both in-process and Kafka-delivered messages.",[555,1241,1242,1247,1248,1251],{},[111,1243,1246],{"href":1244,"rel":1245},"https:\u002F\u002Fgithub.com\u002Fzarusz\u002FSlimMessageBus",[187],"SlimMessageBus"," is a lightweight bus for publish-subscribe and request-response, with a Kafka provider, ",[30,1249,1250],{},"SlimMessageBus.Host.Kafka",". Consider it when you want a lightweight messaging API with pluggable transports and optional outbox support.",[10,1253,1254],{},"Both use Confluent.Kafka underneath.",[42,1256,158],{"id":1257},"stream-processing-in-net",[10,1259,1260],{},"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.",[10,1262,1263,560,1266,1270,1271,1274,1275,1278],{},[14,1264,1265],{},"Stateful processing: aggregations, joins, and windows.",[111,1267,151],{"href":1268,"rel":1269},"https:\u002F\u002Fgithub.com\u002FLGouellec\u002Fstreamiz",[187]," 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 ",[30,1272,1273],{},"Guarantee"," to ",[30,1276,1277],{},"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.\"",[10,1280,1281,560,1284,1289,1290,1293],{},[14,1282,1283],{},"Consumer pipelines with backpressure.",[111,1285,1288],{"href":1286,"rel":1287},"https:\u002F\u002Fgithub.com\u002Fakkadotnet\u002FAkka.Streams.Kafka",[187],"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 ",[30,1291,1292],{},"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.\"",[10,1295,1296,1297,1300],{},"If you need the Java Kafka Streams API itself, ",[111,1298,756],{"href":1299},"#knet-the-java-client-through-a-jvm-bridge"," lets .NET code call Apache's Java library through a JVM hosted in the same process.",[42,1302,1304],{"id":1303},"github-repository-metrics","GitHub repository metrics",[10,1306,1307],{},"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.",[10,1309,1310],{},"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.",[536,1312,1314],{"id":1313},"project-overview","Project overview",[47,1316,1317,1344],{},[50,1318,1319],{},[53,1320,1321,1323,1328,1333,1339],{},[56,1322],{},[56,1324,1325],{},[111,1326,27],{"href":543,"rel":1327},[187],[56,1329,1330],{},[111,1331,36],{"href":993,"rel":1332},[187],[56,1334,1335],{},[111,1336,1338],{"href":1057,"rel":1337},[187],"MassTransit v8",[56,1340,1341],{},[111,1342,90],{"href":665,"rel":1343},[187],[66,1345,1346,1363],{},[53,1347,1348,1351,1354,1357,1360],{},[71,1349,1350],{},"Repository created",[71,1352,1353],{},"1 Nov 2016",[71,1355,1356],{},"2 Jun 2020",[71,1358,1359],{},"16 Jul 2010",[71,1361,1362],{},"21 Jan 2026",[53,1364,1365,1367,1369,1371,1373],{},[71,1366,525],{},[71,1368,528],{},[71,1370,531],{},[71,1372,528],{},[71,1374,531],{},[536,1376,1378],{"id":1377},"activity","Activity",[47,1380,1381,1408],{},[50,1382,1383],{},[53,1384,1385,1388,1393,1398,1403],{},[56,1386,1387],{},"Metric",[56,1389,1390],{},[111,1391,27],{"href":543,"rel":1392},[187],[56,1394,1395],{},[111,1396,36],{"href":993,"rel":1397},[187],[56,1399,1400],{},[111,1401,1338],{"href":1057,"rel":1402},[187],[56,1404,1405],{},[111,1406,90],{"href":665,"rel":1407},[187],[66,1409,1410,1427,1444,1461,1478,1495,1512],{},[53,1411,1412,1415,1418,1421,1424],{},[71,1413,1414],{},"Latest default-branch commit",[71,1416,1417],{},"7 Oct 2026",[71,1419,1420],{},"8 May 2026",[71,1422,1423],{},"27 Sep 2026",[71,1425,1426],{},"9 Oct 2026",[53,1428,1429,1432,1435,1438,1441],{},[71,1430,1431],{},"Latest GitHub Release",[71,1433,1434],{},"v2.16.0 (7 Oct 2026)",[71,1436,1437],{},"4.2.0 (11 Mar 2026)",[71,1439,1440],{},"—",[71,1442,1443],{},"v1.23.3 (9 Oct 2026)",[53,1445,1446,1449,1452,1455,1458],{},[71,1447,1448],{},"GitHub Releases (12 mo)",[71,1450,1451],{},"9",[71,1453,1454],{},"2",[71,1456,1457],{},"0",[71,1459,1460],{},"39",[53,1462,1463,1466,1469,1472,1475],{},[71,1464,1465],{},"Commits",[71,1467,1468],{},"22 (90 d) · 85 (12 mo)",[71,1470,1471],{},"0 (90 d) · 34 (12 mo)",[71,1473,1474],{},"3 (90 d) · 38 (12 mo)",[71,1476,1477],{},"1,295 (90 d) · 3,924 (12 mo)",[53,1479,1480,1483,1486,1489,1492],{},[71,1481,1482],{},"Issue flow (90 d)",[71,1484,1485],{},"2 opened · 3 closed",[71,1487,1488],{},"4 opened · 0 closed",[71,1490,1491],{},"7 opened · 7 closed",[71,1493,1494],{},"566 opened · 559 closed",[53,1496,1497,1500,1503,1506,1509],{},[71,1498,1499],{},"PR flow (90 d)",[71,1501,1502],{},"26 opened · 22 merged",[71,1504,1505],{},"24 opened · 0 merged",[71,1507,1508],{},"5 opened · 0 merged",[71,1510,1511],{},"1,238 opened · 1,197 merged",[53,1513,1514,1517,1520,1523,1526],{},[71,1515,1516],{},"Activity assessment",[71,1518,1519],{},"🟢 22 commits and 22 merged PRs in the last 90 days.",[71,1521,1522],{},"🔴 No commits and no merged PRs in the last 90 days.",[71,1524,1525],{},"🟡 3 commits and 0 merged PRs in the last 90 days.",[71,1527,1528],{},"🟢 1,295 commits and 1,197 merged PRs in the last 90 days.",[10,1530,1531],{},"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.",[536,1533,1535],{"id":1534},"maintenance","Maintenance",[47,1537,1538,1564],{},[50,1539,1540],{},[53,1541,1542,1544,1549,1554,1559],{},[56,1543,1387],{},[56,1545,1546],{},[111,1547,27],{"href":543,"rel":1548},[187],[56,1550,1551],{},[111,1552,36],{"href":993,"rel":1553},[187],[56,1555,1556],{},[111,1557,1338],{"href":1057,"rel":1558},[187],[56,1560,1561],{},[111,1562,90],{"href":665,"rel":1563},[187],[66,1565,1566,1583,1599,1616,1633,1649],{},[53,1567,1568,1571,1574,1577,1580],{},[71,1569,1570],{},"Active commit authors (12 mo)",[71,1572,1573],{},"23",[71,1575,1576],{},"6",[71,1578,1579],{},"5",[71,1581,1582],{},"4",[53,1584,1585,1588,1591,1594,1597],{},[71,1586,1587],{},"PR merge distribution (12 mo)",[71,1589,1590],{},"14 accounts · Top 1: 51% · Top 2: 64%",[71,1592,1593],{},"2 accounts · Top 1: 84% · Top 2: 100%",[71,1595,1596],{},"1 account · 100% of non-bot merges",[71,1598,1596],{},[53,1600,1601,1604,1607,1610,1613],{},[71,1602,1603],{},"Issue backlog",[71,1605,1606],{},"381 open · median age 5.5 y",[71,1608,1609],{},"59 open · median age 2.3 y",[71,1611,1612],{},"1 open · median age 115 d",[71,1614,1615],{},"9 open · median age 41 d",[53,1617,1618,1621,1624,1627,1630],{},[71,1619,1620],{},"PR backlog",[71,1622,1623],{},"92 open · median age 2.9 y",[71,1625,1626],{},"67 open · median age 143 d",[71,1628,1629],{},"1 open · median age 6 d",[71,1631,1632],{},"1 open · median age 3 d",[53,1634,1635,1638,1641,1644,1646],{},[71,1636,1637],{},"Median PR merge time (90 d)",[71,1639,1640],{},"5.4 d (n=22)",[71,1642,1643],{},"N\u002FA — no merged PRs in window",[71,1645,1643],{},[71,1647,1648],{},"\u003C1 h (n=1,197)",[53,1650,1651,1654,1657,1660,1663],{},[71,1652,1653],{},"Responsiveness assessment",[71,1655,1656],{},"🟡 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.",[71,1658,1659],{},"🟡 Median open PR age 143 d exceeds 60 d.",[71,1661,1662],{},"🟢 The median open PR age is 6 d; 10 of 11 issues closed within 90 d.",[71,1664,1665],{},"🟢 For the 1,197 PRs merged in the last 90 d, the median creation-to-merge time was \u003C1 h; the median open PR age is 3 d, and 340 of 341 issues closed within 90 d.",[10,1667,1668,1669,1672],{},"PR merge distribution counts non-bot ",[30,1670,1671],{},"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.",[536,1674,1676],{"id":1675},"public-usage-and-interest","Public usage and interest",[47,1678,1679,1705],{},[50,1680,1681],{},[53,1682,1683,1685,1690,1695,1700],{},[56,1684,1387],{},[56,1686,1687],{},[111,1688,27],{"href":543,"rel":1689},[187],[56,1691,1692],{},[111,1693,36],{"href":993,"rel":1694},[187],[56,1696,1697],{},[111,1698,1338],{"href":1057,"rel":1699},[187],[56,1701,1702],{},[111,1703,90],{"href":665,"rel":1704},[187],[66,1706,1707,1724,1740],{},[53,1708,1709,1712,1715,1718,1721],{},[71,1710,1711],{},"Stars",[71,1713,1714],{},"278",[71,1716,1717],{},"782",[71,1719,1720],{},"7,803",[71,1722,1723],{},"88",[53,1725,1726,1729,1732,1735,1738],{},[71,1727,1728],{},"Forks",[71,1730,1731],{},"900",[71,1733,1734],{},"147",[71,1736,1737],{},"1,972",[71,1739,1579],{},[53,1741,1742,1745,1748,1751,1754],{},[71,1743,1744],{},"GitHub dependents (Used by)",[71,1746,1747],{},"11,988",[71,1749,1750],{},"176",[71,1752,1753],{},"13,403",[71,1755,1576],{},[10,1757,1758],{},"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.",[536,1760,1762],{"id":1761},"other-recommended-options","Other recommended options",[47,1764,1765,1792],{},[50,1766,1767],{},[53,1768,1769,1771,1776,1781,1786],{},[56,1770,1387],{},[56,1772,1773],{},[111,1774,1156],{"href":1161,"rel":1775},[187],[56,1777,1778],{},[111,1779,1216],{"href":1214,"rel":1780},[187],[56,1782,1783],{},[111,1784,1208],{"href":1206,"rel":1785},[187],[56,1787,1788],{},[111,1789,1791],{"href":1268,"rel":1790},[187],"Streamiz",[66,1793,1794,1808,1824,1838,1854,1870],{},[53,1795,1796,1798,1800,1802,1805],{},[71,1797,1414],{},[71,1799,1426],{},[71,1801,1417],{},[71,1803,1804],{},"26 Sep 2026",[71,1806,1807],{},"23 Sep 2026",[53,1809,1810,1812,1815,1818,1821],{},[71,1811,1431],{},[71,1813,1814],{},"V6.48.2 (9 Oct 2026)",[71,1816,1817],{},"v10.0.2 (1 Aug 2026)",[71,1819,1820],{},"v5.5.2 (10 Sep 2026)",[71,1822,1823],{},"v1.8.2 (24 Sep 2026)",[53,1825,1826,1828,1831,1833,1836],{},[71,1827,1448],{},[71,1829,1830],{},"145",[71,1832,1582],{},[71,1834,1835],{},"16",[71,1837,1582],{},[53,1839,1840,1842,1845,1848,1851],{},[71,1841,1465],{},[71,1843,1844],{},"1,352 (90 d) · 3,453 (12 mo)",[71,1846,1847],{},"5 (90 d) · 39 (12 mo)",[71,1849,1850],{},"55 (90 d) · 146 (12 mo)",[71,1852,1853],{},"19 (90 d) · 88 (12 mo)",[53,1855,1856,1858,1861,1864,1867],{},[71,1857,1499],{},[71,1859,1860],{},"869 opened · 834 merged",[71,1862,1863],{},"6 opened · 0 merged",[71,1865,1866],{},"2 opened · 1 merged",[71,1868,1869],{},"5 opened · 5 merged",[53,1871,1872,1874,1877,1880,1883],{},[71,1873,1711],{},[71,1875,1876],{},"2,378",[71,1878,1879],{},"7,112",[71,1881,1882],{},"285",[71,1884,1885],{},"545",[10,1887,1888],{},"Wolverine, CAP, and Silverback figures cover their other transports as well as Kafka.",[536,1890,1892],{"id":1891},"nuget-downloads","NuGet downloads",[47,1894,1895,1908],{},[50,1896,1897],{},[53,1898,1899,1902,1905],{},[56,1900,1901],{},"Package",[56,1903,1904],{},"Library",[56,1906,1907],{},"Total downloads",[66,1909,1910,1923,1937,1950,1963,1977,1991,2004,2017,2031,2044,2057],{},[53,1911,1912,1918,1920],{},[71,1913,1914],{},[111,1915,27],{"href":1916,"rel":1917},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FConfluent.Kafka",[187],[71,1919,27],{},[71,1921,1922],{},"277.4M",[53,1924,1925,1932,1934],{},[71,1926,1927],{},[111,1928,1931],{"href":1929,"rel":1930},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FMassTransit.Kafka",[187],"MassTransit.Kafka",[71,1933,1052],{},[71,1935,1936],{},"14.6M",[53,1938,1939,1945,1947],{},[71,1940,1941],{},[111,1942,36],{"href":1943,"rel":1944},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FKafkaFlow",[187],[71,1946,36],{},[71,1948,1949],{},"12.6M",[53,1951,1952,1958,1960],{},[71,1953,1954],{},[111,1955,760],{"href":1956,"rel":1957},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FMASES.KNet",[187],[71,1959,756],{},[71,1961,1962],{},"3.0M",[53,1964,1965,1972,1974],{},[71,1966,1967],{},[111,1968,1971],{"href":1969,"rel":1970},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FDotNetCore.CAP.Kafka",[187],"DotNetCore.CAP.Kafka",[71,1973,1216],{},[71,1975,1976],{},"2.8M",[53,1978,1979,1986,1988],{},[71,1980,1981],{},[111,1982,1985],{"href":1983,"rel":1984},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FSilverback.Integration.Kafka",[187],"Silverback.Integration.Kafka",[71,1987,1208],{},[71,1989,1990],{},"1.5M",[53,1992,1993,1999,2001],{},[71,1994,1995],{},[111,1996,151],{"href":1997,"rel":1998},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FStreamiz.Kafka.Net",[187],[71,2000,1791],{},[71,2002,2003],{},"1.2M",[53,2005,2006,2012,2014],{},[71,2007,2008],{},[111,2009,1288],{"href":2010,"rel":2011},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FAkka.Streams.Kafka",[187],[71,2013,1288],{},[71,2015,2016],{},"938.7K",[53,2018,2019,2026,2028],{},[71,2020,2021],{},[111,2022,2025],{"href":2023,"rel":2024},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FWolverineFx.Kafka",[187],"WolverineFx.Kafka",[71,2027,1156],{},[71,2029,2030],{},"594.9K",[53,2032,2033,2039,2041],{},[71,2034,2035],{},[111,2036,1250],{"href":2037,"rel":2038},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FSlimMessageBus.Host.Kafka",[187],[71,2040,1246],{},[71,2042,2043],{},"518.8K",[53,2045,2046,2052,2054],{},[71,2047,2048],{},[111,2049,1238],{"href":2050,"rel":2051},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FParamore.Brighter.MessagingGateway.Kafka",[187],[71,2053,1234],{},[71,2055,2056],{},"198.0K",[53,2058,2059,2065,2067],{},[71,2060,2061],{},[111,2062,90],{"href":2063,"rel":2064},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FDekaf",[187],[71,2066,90],{},[71,2068,2069],{},"96.0K",[10,2071,2072],{},"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.",[536,2074,2076],{"id":2075},"overall-repository-signals","Overall repository signals",[552,2078,2079,2084,2089,2094,2099],{},[555,2080,2081,2083],{},[14,2082,27],{}," 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.",[555,2085,2086,2088],{},[14,2087,36],{}," has 12.6M downloads and 176 GitHub dependents, but no commits or merged PRs in the last 90 days, with 67 PRs still open.",[555,2090,2091,2093],{},[14,2092,1338],{}," 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.",[555,2095,2096,2098],{},[14,2097,90],{}," 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.",[555,2100,2101,2104],{},[14,2102,2103],{},"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.",[10,2106,2107],{},"These are maintenance and adoption signals, not evidence of runtime quality or feature fit.",[42,2109,2111],{"id":2110},"test-net-kafka-clients-with-kafma","Test .NET Kafka clients with Kafma",[10,2113,2114],{},"Before you pick a library or switch producers, check four things on a test cluster: failure handling, framework headers, commit timing, and partition placement.",[10,2116,2117,2118,2122,2123,2127],{},"Kafma is a desktop ",[111,2119,2121],{"href":2120},"\u002F","Kafka GUI"," that runs next to your .NET service. In its ",[111,2124,2126],{"href":2125},"\u002Ffeatures\u002Fkafka-console","Kafka console",", you can send test records, inspect what a producer wrote, and watch a consumer group's committed offsets.",[10,2129,2130],{},[2131,2132],"img",{"alt":2133,"height":2134,"src":2135,"width":2136},"Kafma console with topic tabs, a live message stream, and a producer with partition, headers, and Loop controls",1898,"https:\u002F\u002Fmedia.kafma.app\u002Fchangelog\u002Fv1.0.0\u002Fhomepage-hero.png",3024,[536,2138,2140],{"id":2139},"test-handler-failures","Test handler failures",[10,2142,2143,2144,2148,2149,2153],{},"From the ",[111,2145,2147],{"href":2146},"\u002Fdocs\u002Fconsole\u002Fproducing-messages","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 ",[111,2150,2152],{"href":2151},"\u002Fdocs\u002Fconsole\u002Fconsuming-messages#live-and-watch-group-modes","Watch Group"," whether the committed offset moves past the failing record. With default settings:",[552,2155,2156,2163,2168,2173,2178],{},[555,2157,2158,301,2160,2162],{},[14,2159,27],{},[14,2161,36],{}," can commit it even though the handler failed.",[555,2164,2165,2167],{},[14,2166,90],{}," can commit it if your loop catches the exception and continues.",[555,2169,2170,2172],{},[14,2171,1052],{}," discards it; in v9.2+, an error topic is opt-in.",[555,2174,2175,2177],{},[14,2176,1208],{}," stops the consumer, so the offset does not move past it.",[555,2179,2180,2182],{},[14,2181,1156],{}," 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.",[10,2184,2185],{},"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.",[536,2187,2189],{"id":2188},"check-framework-headers","Check framework headers",[10,2191,2192,2193,301,2195,2197,2198,2200],{},"Open a record the framework wrote to see its headers. MassTransit adds ",[30,2194,1116],{},[30,2196,1124],{},", KafkaFlow's default type resolver adds ",[30,2199,1029],{},", and CAP adds its own metadata headers.",[10,2202,2203,2204,2208,2209,2212,2213,2216],{},"To find which headers your consumer needs, ",[111,2205,2207],{"href":2206},"\u002Fdocs\u002Fconsole\u002Freplay-forward-and-export","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 ",[14,2210,2211],{},"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: ",[30,2214,2215],{},"00"," followed by four ID bytes.",[10,2218,2219],{},[2131,2220],{"alt":2221,"height":2222,"src":2223,"width":2224},"Kafma message details showing record headers, an Avro schema ID, and the Decoded and Raw views",778,"https:\u002F\u002Fmedia.kafma.app\u002Fblog\u002Fkafka-dotnet-clients\u002Fdecode.png",1398,[536,2226,2228],{"id":2227},"check-commits-and-restarts","Check commits and restarts",[10,2230,2231,2232,2235],{},"Use ",[14,2233,2234],{},"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.",[10,2237,2238,2239,2243],{},"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 ",[111,2240,2242],{"href":2241},"\u002Ffeatures\u002Fkafka-consumer-groups","consumer group UI"," shows lag by topic, partition, and member.",[10,2245,2246],{},[2131,2247],{"alt":2248,"height":2249,"src":2250,"width":2251},"Kafma watching pending and consumed records around a consumer group's committed offsets",1368,"https:\u002F\u002Fmedia.kafma.app\u002Fdocs\u002Fconsole\u002Fconsuming-messages\u002Fwatch-group.png",1562,[536,2253,2255],{"id":2254},"compare-partitions-across-producers","Compare partitions across producers",[10,2257,2258,2259,2262],{},"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 ",[14,2260,2261],{},"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.",[10,2264,2265,2266,2268],{},"When sharing a topic with Java producers, set ",[30,2267,625],{}," in Confluent.Kafka to align keyed partitioning.",[10,2270,2271,2275],{},[111,2272,2274],{"href":2273},"\u002Fdownload","Download Kafma"," and connect it to the same test cluster as your .NET service.",[42,2277,2279],{"id":2278},"frequently-asked-questions","Frequently asked questions",[536,2281,2283],{"id":2282},"is-there-an-official-apache-kafka-client-for-net","Is there an official Apache Kafka client for .NET?",[10,2285,2286],{},"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.",[536,2288,2290],{"id":2289},"how-do-i-fix-failed-to-load-the-librdkafka-native-library","How do I fix \"Failed to load the librdkafka native library\"?",[10,2292,2293,2294,2296,2297,2299],{},"Check that your platform is one ",[30,2295,369],{}," 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 ",[30,2298,586],{}," with its path before creating a client, or use Dekaf, which has no native library.",[536,2301,2303],{"id":2302},"does-confluentkafka-support-async-consume","Does Confluent.Kafka support async consume?",[10,2305,2306,2307,2309,2310,2312,2313,2315,2316,115],{},"No. ",[30,2308,210],{}," 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 ",[30,2311,563],{},". Dekaf provides an async ",[30,2314,417],{}," that returns ",[30,2317,96],{},[536,2319,2321],{"id":2320},"which-net-kafka-clients-support-kip-848","Which .NET Kafka clients support KIP-848?",[10,2323,2324,2325,2327],{},"Confluent.Kafka 2.12.0 and later, with ",[30,2326,613],{}," 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.",[536,2329,2331],{"id":2330},"do-net-kafka-clients-partition-keys-the-same-way-as-java","Do .NET Kafka clients partition keys the same way as Java?",[10,2333,2334,2335,2337],{},"Not all of them. Confluent.Kafka and the frameworks built on it hash non-empty keys with CRC32 by default; set ",[30,2336,625],{}," 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.",[536,2339,2341],{"id":2340},"how-do-i-use-kafka-with-net-aspire","How do I use Kafka with .NET Aspire?",[10,2343,2344,2345,2348,2349,2352,2353,2356,2357,2348,2360,2363,2364,2367],{},"In the AppHost, use ",[30,2346,2347],{},"Aspire.Hosting.Kafka"," with ",[30,2350,2351],{},"AddKafka",", and reference the resource from each service with ",[30,2354,2355],{},"WithReference",". In the service, use ",[30,2358,2359],{},"Aspire.Confluent.Kafka",[30,2361,2362],{},"AddKafkaProducer"," or ",[30,2365,2366],{},"AddKafkaConsumer"," and the same resource name to get dependency injection, health checks, and telemetry. The application still owns the consumer loop.",[536,2369,2371],{"id":2370},"is-kafkaflow-still-maintained","Is KafkaFlow still maintained?",[10,2373,2374],{},"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.",[42,2376,2378],{"id":2377},"conclusion","Conclusion",[10,2380,2381],{},"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.",[10,2383,2384],{},"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.",[10,2386,2387],{},"This guide is maintained by the team behind Kafma.",{"title":2389,"searchDepth":2390,"depth":2390,"links":2391},"",3,[2392,2394,2395,2400,2407,2408,2417,2423,2432],{"id":44,"depth":2393,"text":45},2,{"id":164,"depth":2393,"text":165},{"id":326,"depth":2393,"text":327,"children":2396},[2397,2398,2399],{"id":538,"depth":2390,"text":27},{"id":660,"depth":2390,"text":90},{"id":748,"depth":2390,"text":749},{"id":773,"depth":2393,"text":774,"children":2401},[2402,2403,2404,2405,2406],{"id":988,"depth":2390,"text":36},{"id":1051,"depth":2390,"text":1052},{"id":1155,"depth":2390,"text":1156},{"id":1200,"depth":2390,"text":1201},{"id":1224,"depth":2390,"text":1225},{"id":1257,"depth":2393,"text":158},{"id":1303,"depth":2393,"text":1304,"children":2409},[2410,2411,2412,2413,2414,2415,2416],{"id":1313,"depth":2390,"text":1314},{"id":1377,"depth":2390,"text":1378},{"id":1534,"depth":2390,"text":1535},{"id":1675,"depth":2390,"text":1676},{"id":1761,"depth":2390,"text":1762},{"id":1891,"depth":2390,"text":1892},{"id":2075,"depth":2390,"text":2076},{"id":2110,"depth":2393,"text":2111,"children":2418},[2419,2420,2421,2422],{"id":2139,"depth":2390,"text":2140},{"id":2188,"depth":2390,"text":2189},{"id":2227,"depth":2390,"text":2228},{"id":2254,"depth":2390,"text":2255},{"id":2278,"depth":2393,"text":2279,"children":2424},[2425,2426,2427,2428,2429,2430,2431],{"id":2282,"depth":2390,"text":2283},{"id":2289,"depth":2390,"text":2290},{"id":2302,"depth":2390,"text":2303},{"id":2320,"depth":2390,"text":2321},{"id":2330,"depth":2390,"text":2331},{"id":2340,"depth":2390,"text":2341},{"id":2370,"depth":2390,"text":2371},{"id":2377,"depth":2393,"text":2378},"2026-10-09","MassTransit v9 is now commercial. Compare Kafka clients for C# and .NET: Confluent.Kafka, KafkaFlow, MassTransit, and Dekaf.","md",{},true,null,"\u002Fblog\u002Fkafka-dotnet-clients",false,{"title":5,"description":2434},{"loc":2439},"blog\u002Fkafka-dotnet-clients",[2445,2446],"Kafka Client Libraries",".NET","8c1GCyPNrs1v4HfKdyWgcXN0SQzMNQ6CQ9uAHpFXwfk",1791544592146]