u/Bitter_Session3161

▲ 14 r/nestjs

NestJS still ships its Kafka transport on kafkajs (unmaintained). I wrote a drop-in replacement on @platformatic/kafka that stays wire-compatible, so you can migrate one service at a time.

reddit.com
u/Bitter_Session3161 — 13 days ago
▲ 17 r/Nestjs_framework+1 crossposts

The NestJS Kafka transport still runs on unmaintained kafkajs. I built a drop-in replacement that stays wire-compatible, so you can migrate one service at a time

Two years, 60+ comments, no shipped fix. That's the state of the NestJS issue asking to stop depending on kafkajs: https://github.com/nestjs/nest/issues/13223

Core won't swap it (backwards compatibility). The maintainer suggested "a separate transport strategy so people migrate over time". The one snippet posted was event-only and, quoting a team that tried it in production, "full of any, no reconnection support".

So I built that transport: nestjs-kafka-transport, on top of u/platformatic/kafka (pure JS, written by Node core contributors).

Repo: https://github.com/fadiroot/nestjs-kafka-transport

npm: https://www.npmjs.com/package/nestjs-kafka-transport

The part that matters: it speaks the exact same wire format as the built-in transport. Same kafka_correlationId / kafka_replyTopic / kafka_replyPartition headers, same <pattern>.reply topics, same parser rules. A service on the new transport talks to services still on Transport.KAFKA. There are e2e tests for both directions (kafkajs ClientKafka to the new server, the new client to the built-in ServerKafka). Migrate consumers first, one service at a time, no big bang.

Your controllers don't change; only main.ts does:

before: { transport: Transport.KAFKA, options: { client: { brokers }, consumer: { groupId: 'orders' } } }

after: { strategy: new KafkaTransportServer({ client: { bootstrapBrokers: brokers }, consumer: { groupId: 'orders' } }) }

What you get on top:

• Request-reply with a real reply-partition assigner (every client owns a partition of each reply topic; that's what the snippet in the thread was missing).

• KafkaRetriableException → re-run with exponential backoff; offsets committed after each handled record (at-least-once); per-partition ordering preserved.

• Numbers, booleans and null come back as numbers, booleans and null, not "6", via a content-type header that kafkajs peers simply ignore.

• Options typed all the way down, no any in the public API. CI on Node 22/24 against Kafka 3.9 and 4.0.

Honest limits: v0.1. Node 22.22 or newer (Platformatic's floor). RegExp patterns resolve against topics that exist at startup. Next: dead-letter/retry topics with Nest's kafka_dlt-* headers, manual commits, batch handlers, OpenTelemetry, in that order unless you tell me otherwise.

If you run NestJS + Kafka in production: try it on one consumer and tell me what breaks. I'll be in the comments.

u/Bitter_Session3161 — 16 days ago