Dev Encyclopedia
ArticlesToolsContactAbout

Get notified when new content drops

No spam. Just new articles, tools, and updates straight to your inbox.

Dev Encyclopedia

A reference for builders

Dev.to
Discord
WhatsApp Channel
daily.dev
Hashnode
X

Content

  • Articles
  • Tools
  • About
  • Contact

Connect

  • support@devencyclopedia.com
  • RSS Feed

Legal

  • Privacy Policy
  • Terms of Service
  • Disclaimer

© 2026 Dev Encyclopedia

Back to top ↑
  1. Home
  2. /Blog
  3. /Apache Kafka with Node.js: Complete Setup Guide (2026)
nodejs19 min read

Apache Kafka with Node.js: Complete Setup Guide (2026)

Learn Kafka with Node.js step by step: core concepts, local Docker setup, real KafkaJS code, and when to use it in a monolith vs microservices.

Zeeshan Tofiq
Zeeshan Tofiq
October 7, 2026
On this page

On this page

  • What Kafka Actually Solves
  • The Core Concepts, One Example Throughout
  • What You Would Actually Use Kafka For
  • Running Kafka Locally With Docker and Node.js
  • Making the Producer Actually Reliable
  • Consumer Groups and Scaling, In Practice
  • Monolith or Microservices? Where Kafka Fits
  • Common Mistakes That Cost People Messages
  • Frequently Asked Questions

If two parts of your app both need to know when something happens, you already understand the problem Kafka solves. A customer places an order. Your email service needs to send a confirmation. Your inventory service needs to decrement stock. Your analytics pipeline wants the event too.

The obvious solution is to call all three from your order handler. That works until you add a fourth listener, then a fifth. Now your order handler imports half the codebase, and one slow downstream call holds up the HTTP response the customer is waiting on.

Kafka flips the direction. Your order handler publishes one event and stops caring. Anyone who needs it subscribes and reads it on their own schedule. This guide takes you from that idea to working Kafka with Node.js code, running locally on Docker, then answers the question most Kafka tutorials skip entirely: do you actually need microservices to use it?

💡 TL;DR

Kafka is a durable, replayable log that many consumers can read independently. Run it locally with one docker-compose.yml in KRaft mode (no Zookeeper in 2026). Talk to it from Node.js with kafkajs. And no, you do not need microservices first: Kafka inside a single Express or NestJS app is a legitimate and underrated pattern.

Diagram of an order service publishing a single order-placed event to a Kafka topic, with three independent consumers reading from that topic: an email service, an inventory service, and an analytics service
One event published once. Three consumers read it independently, and the producer never knows they exist.

What Kafka Actually Solves

The textbook definition is that Kafka is a distributed commit log. That is accurate and completely useless if you have never used one, so park it for a moment.

Here is the practical version. Kafka is an append-only log that lives on a server. Producers append records to the end of it. Consumers read through it at their own pace, keeping track of how far they have got. Records do not disappear when someone reads them, which is the single most important difference between Kafka and a traditional message queue.

That one property is what makes everything else possible. Because the log persists, a new consumer can join next month and replay every event from the beginning. A consumer that crashes can restart and pick up exactly where it stopped. Three different teams can read the same stream without coordinating with each other or with the producer.

Direct HTTP calls between servicesPublishing events to Kafka
Who knows about whomThe caller must know every listener's URL and contractThe producer knows only the topic name
Adding a new listenerRequires a code change and redeploy of the callerNew consumer subscribes; producer is untouched
If a listener is downThe call fails, and you own the retry logicThe event waits in the log until the consumer returns
Latency felt by the userSum of every downstream callOne local write, then the request returns
Replaying past eventsNot possible without a custom audit tableBuilt in; reset the offset and read again
Operational costNone beyond the services you already runA cluster to run, monitor, and size

That last row matters. Kafka is not free. You are trading a simple function call for a piece of infrastructure that needs to be running, monitored, and understood by whoever is on call. The rest of this guide is partly about when that trade is worth making.

The Core Concepts, One Example Throughout

Every Kafka explainer drowns you in vocabulary on page one. Instead, here is one running example (an online store) with each term introduced only where it earns its place.

  • Producer is any code that sends events. When a customer checks out, your order service is the producer.
  • Topic is the named log events get written to, for example order-placed. Producers write to it, consumers read from it, and it is the only name either side needs to agree on.
  • Consumer is code that reads from a topic. Your email service and your inventory service are both consumers of order-placed.
  • Partition is how one topic is split so it can be read in parallel. A topic with 3 partitions can be processed by 3 workers at once.
  • Offset is a consumer's bookmark: the position it has read up to in a given partition. Kafka stores this per consumer group, which is how a restarted consumer resumes instead of starting over.
  • Broker is one Kafka server. A cluster is several brokers sharing the work and replicating each other's data.
  • Consumer group is a set of consumers that share a topic's partitions between them, so each event is handled once by the group rather than once per instance.
Diagram of a Kafka topic named order-placed split into three partitions, each showing numbered offset slots holding order records, with a consumer group of two instances where one consumer is assigned two partitions and the other is assigned one
A topic is a group of partitions. Order is guaranteed inside a partition, never across the whole topic.

Partitions are where most beginners get burned, so it is worth slowing down. When you publish a message with a key, Kafka hashes that key to pick a partition. Same key always lands in the same partition, which means all events for order 1001 are processed in the order you sent them.

Publish without a key and Kafka spreads messages across partitions for throughput. That is fine for independent events like page views, and quietly wrong for anything where sequence matters. If you send order-created and order-cancelled with no key, a consumer can genuinely process the cancellation first.

⚠ The ordering rule in one sentence

Kafka guarantees ordering within a single partition only. If two events must be processed in order, they must share a partition key, usually the entity ID they both belong to.

What You Would Actually Use Kafka For

Generic lists of Kafka use cases are not much help. Here are the concrete ones a Node.js developer is likely to recognise, with what the topic and key look like in each.

Six patterns that come up repeatedly in Node.js backends.
ScenarioTopic and keyWhy Kafka over a plain job queue
Order fanoutorder-placed, keyed by order IDSeveral unrelated consumers need the same event, and new ones get added over time
Activity and analytics trackinguser-activity, no keyVery high write volume, and you want to replay history into a new dashboard later
Search index updatesproduct-updated, keyed by product IDOrdering per product matters, and a full reindex is just a replay from offset zero
Audit and event sourcingaccount-events, keyed by account IDRetention is the point: the log itself is the record of what happened
Decoupling modules in one appreport-requested, keyed by user IDSlow work leaves the request path without adding a separate service to deploy
Cross-service contractspayment-settled, keyed by payment IDTeams agree on an event shape instead of sharing code or calling each other directly

Notice how many of these have nothing to do with microservices. Kafka is often introduced as a microservices tool, but half of its value is available inside a single deployable app.

It is also worth being honest about where Kafka is the wrong answer. If you need one worker to pick up one job and you care about per-job retries, delays, and priorities, a job queue backed by Redis is a simpler fit. Kafka has no per-message acknowledgement and no built-in delayed delivery.

Running Kafka Locally With Docker and Node.js

This section takes you from an empty folder to messages flowing between two Node.js processes. Everything runs on your machine, and you need only Docker and Node.js 18 or newer installed.

One thing to skip before you start: almost every older tutorial sets up Zookeeper alongside Kafka. Since Kafka 3.x, KRaft mode removes that dependency, and Zookeeper support was removed entirely in Kafka 4.0. If a guide tells you to run a zookeeper container in 2026, it is out of date.

  1. 1

    Start a single-broker Kafka in KRaft mode

    Create a docker-compose.yml in an empty folder. This runs one container acting as both broker and controller, which is exactly what you want locally and never what you want in production.

    yaml — docker-compose.yml
    services:
      kafka:
        image: apache/kafka:latest
        container_name: kafka
        ports:
          - "9092:9092"
        environment:
          KAFKA_NODE_ID: 1
          KAFKA_PROCESS_ROLES: broker,controller
          KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093
          KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
          KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
          KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
          KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
          KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
          KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
          KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0

    Bring it up in the background:

    bash
    docker compose up -d

    ℹ Info

    The three replication-factor and rebalance settings at the bottom are not optional decoration. Kafka's internal topics default to a replication factor of 3, and a single broker cannot satisfy that, so the broker starts and then fails the moment a consumer group forms.

  2. 2

    Create the topic with more than one partition

    Kafka can auto-create topics, but it gives them one partition, which caps your consumer group at one active instance forever. Create it explicitly instead:

    bash
    docker exec -it kafka /opt/kafka/bin/kafka-topics.sh \
      --create \
      --topic order-placed \
      --bootstrap-server localhost:9092 \
      --partitions 3 \
      --replication-factor 1

    Confirm it exists and check what Kafka actually gave you:

    bash
    docker exec -it kafka /opt/kafka/bin/kafka-topics.sh \
      --describe --topic order-placed \
      --bootstrap-server localhost:9092

    You should see three lines, one per partition, each listing a leader and its replicas. If that command returns cleanly, Kafka is up and your local setup is done.

  3. 3

    Install KafkaJS

    There are three Node.js clients worth knowing about, and the choice is easier than it looks.

    • `kafkajs` is pure JavaScript with no native build step, actively maintained, and has the best documentation. This is the default choice.
    • `node-rdkafka` wraps the C library librdkafka. It is faster under heavy load but needs native compilation, which turns Docker builds and CI into a chore.
    • `kafka-node` is the original client and has been effectively unmaintained for years. Do not start a new project with it.
    bash
    npm init -y
    npm install kafkajs
  4. 4

    Write the producer

    The important detail here is the key. Passing the order ID guarantees every event for that order lands in the same partition and is therefore processed in order.

    javascript — producer.js
    const { Kafka } = require("kafkajs");
    
    const kafka = new Kafka({
      clientId: "order-service",
      brokers: ["localhost:9092"],
    });
    
    const producer = kafka.producer();
    
    async function main() {
      await producer.connect();
    
      const order = { id: "1001", item: "Mechanical Keyboard", total: 89.99 };
    
      await producer.send({
        topic: "order-placed",
        messages: [{ key: order.id, value: JSON.stringify(order) }],
      });
    
      console.log("Published order", order.id);
      await producer.disconnect();
    }
    
    main().catch(async (err) => {
      console.error("Producer failed:", err);
      await producer.disconnect();
      process.exit(1);
    });

    ⚠ Warning

    Connect once at startup and reuse the producer. Calling connect() and disconnect() inside a request handler opens a fresh TCP connection and metadata fetch per message, which is slow enough to notice under any real traffic.

  5. 5

    Write the consumer

    The groupId is the most consequential line in this file. It is how Kafka tracks your offsets, so it must be stable across restarts and deploys. Generating it at runtime means every restart is treated as a brand new consumer.

    javascript — consumer.js
    const { Kafka } = require("kafkajs");
    
    const kafka = new Kafka({
      clientId: "email-service",
      brokers: ["localhost:9092"],
    });
    
    const consumer = kafka.consumer({ groupId: "email-service-group" });
    
    async function main() {
      await consumer.connect();
      await consumer.subscribe({ topic: "order-placed", fromBeginning: true });
    
      await consumer.run({
        eachMessage: async ({ topic, partition, message }) => {
          try {
            const order = JSON.parse(message.value.toString());
            console.log(
              `[p${partition} @${message.offset}] confirmation email for order ${order.id}`
            );
          } catch (err) {
            // A malformed record must not stall the partition forever.
            console.error("Skipping unprocessable message:", err.message);
          }
        },
      });
    }
    
    main().catch(console.error);
    
    for (const signal of ["SIGINT", "SIGTERM"]) {
      process.on(signal, async () => {
        await consumer.disconnect();
        process.exit(0);
      });
    }

    ℹ Info

    The signal handlers are not boilerplate. Disconnecting cleanly tells Kafka to rebalance immediately instead of waiting for the session timeout to expire, which is the difference between a one second and a thirty second gap in processing during a deploy.

  6. 6

    Run both and watch the message flow

    Start the consumer first so it is subscribed and assigned partitions before anything is published. In a second terminal, run the producer.

    bash
    # terminal 1
    node consumer.js
    
    # terminal 2
    node producer.js

    The consumer logs the order within a few milliseconds of the producer publishing it, along with the partition and offset it came from. Those two numbers are worth logging in real systems too: when something goes wrong, the partition and offset are how you find the exact record.

    Two side by side terminal windows, the left running node producer.js and printing Published order 1001, the right running node consumer.js and printing a confirmation email log line with the partition and offset of the received message
    Producer on the left, consumer on the right. The partition and offset in the consumer log are your debugging handles.

Making the Producer Actually Reliable

The producer above works, and it is also where most tutorials stop. The gap between that code and something you would trust with real orders comes down to three settings.

javascript — producer.js
const producer = kafka.producer({
  // Refuse to report success until every in-sync replica has the record.
  idempotent: true,
  maxInFlightRequests: 5,
  retry: { retries: 8, initialRetryTime: 300 },
});

await producer.send({
  topic: "order-placed",
  acks: -1,
  messages: [{ key: order.id, value: JSON.stringify(order) }],
});
  • `acks: -1` (equivalent to acks: 'all') makes the broker wait until every in-sync replica has written the record before acknowledging. With the default of acks: 1, only the partition leader has to confirm, so a leader crash immediately after a write loses the message silently.
  • `idempotent: true` attaches a producer ID and sequence number to every record so the broker can discard duplicates. Without it, a retry after a timeout that actually succeeded writes the same order twice.
  • `retry` controls how long KafkaJS keeps trying through a broker restart or leader election. The default of 5 attempts is usually short for a rolling cluster upgrade.

🚫 Silent data loss is the default

Nothing in Kafka warns you about acks: 1. The producer returns successfully, your logs look clean, and the message is simply not there. Set acks: -1 on any topic where losing a record would be a real incident.

Consumer Groups and Scaling, In Practice

Run two copies of consumer.js with the same groupId and Kafka splits the three partitions between them. One instance gets two partitions, the other gets one. Each message is still handled exactly once by the group.

Change the groupId on the second instance instead, and the behaviour flips completely: both instances now receive every message, because they are two independent groups reading the same log. That is the mechanism behind the fanout in the first diagram.

Partition count is a hard ceiling on how far a consumer group can scale out.
PartitionsConsumers in the groupResult
31One instance reads all three partitions
32One instance gets 2 partitions, the other gets 1
33Perfectly balanced, one partition each
34The fourth instance sits idle and does nothing
1any numberOnly one instance ever works; scaling is impossible

That last row is the practical reason the setup step created three partitions instead of accepting the default. Partitions can be added to an existing topic later, but doing so changes which partition a given key hashes to, which breaks per-key ordering for records already in the log. Over-provision slightly at creation time instead.

A reasonable starting point: set the partition count to the maximum number of consumer instances you expect within the next year, with a floor of 3. Going from 3 to 6 costs almost nothing on a small cluster. Going from 1 to 3 after you are live costs you an ordering guarantee.

Monolith or Microservices? Where Kafka Fits

This is the question that actually decides whether Kafka helps you, and it is the one most tutorials never touch.

The assumption baked into most Kafka content is that you are already running microservices, or that adopting Kafka means you should be. Neither is true. Kafka inside a monolith is a legitimate architecture, and for small teams it is usually the better first move.

Side by side architecture comparison: on the left a single deployed Node.js application whose internal modules publish and consume events through Kafka, on the right three separately deployed microservices communicating only through Kafka topics
Same event log, two very different operational footprints. The left one is one deploy, one log stream, one stack trace.
Kafka inside a monolithKafka between microservices
What you deployOne app, plus a Kafka clusterSeveral apps, plus a Kafka cluster
Local developmentnpm run dev and one containerSeveral processes, or a full Compose stack per developer
Debugging a failed orderOne log stream, often one stack traceCorrelate trace IDs across separate deployed processes
Schema changesProducer and consumer ship together in the same commitNeeds versioning and a compatible rollout order
ScalingScale the whole app, even if one module is the bottleneckScale only the consumer that is actually saturated
Team ownershipOne codebase, coordinate through pull requestsIndependent teams, coordinate through the event contract
Blast radius of a bad deployThe whole applicationOne service; others keep consuming from the log

Use Kafka inside a monolith when you want slow work off the request path (sending email, generating reports, updating a search index), when you want an event log you can replay or audit, or when modules are too tangled but you are not ready to run and monitor several services. You get the decoupling and the durable log without the operational tax.

Split into services when the pressure is organisational or economic rather than architectural: different teams need to ship on independent schedules, one workload genuinely needs different hardware or scaling behaviour than the rest, or a single noisy module is destabilising unrelated features on every deploy. If you are taking that route, our guide to building Node.js microservices without Express covers the service side, and if you are on NestJS its microservices module speaks Kafka natively, which comes up often in NestJS interview questions.

  • Two or more teams are blocked on each other's release schedule
  • One module needs to scale independently and measurably differently from the rest
  • You already have centralised logging with correlation IDs across processes
  • You have someone who can own Kafka in production, including partition sizing and consumer lag alerts
  • Your deploy pipeline can roll out services independently without manual coordination
  • Event schemas are versioned, with a plan for consumers running older versions

If you cannot tick at least four of those, adding Kafka to the app you already have will get you most of the benefit at a fraction of the cost. The event boundaries you define now become your service boundaries later, and drawing them inside one codebase is far cheaper than discovering they were wrong across five deployments.

Common Mistakes That Cost People Messages

  • Leaving `acks` at the default. The producer reports success, the leader dies, the record is gone. Set acks: -1 on anything that matters.
  • Creating topics with one partition. Auto-creation gives you one, and it permanently caps that consumer group at a single working instance.
  • Generating the `groupId` at runtime. Something like email-service-${Date.now()} means every restart is a new group with no stored offsets, so it reprocesses the entire topic or skips everything, depending on fromBeginning.
  • Publishing ordered events without a key. Related events scatter across partitions and get processed out of sequence. Key by the entity ID.
  • Letting `eachMessage` throw. An unhandled rejection stops the partition, and a genuinely unprocessable record blocks every message behind it forever. Catch, log, and route to a dead letter topic.
  • Doing slow work synchronously inside `eachMessage`. Kafka rebalances the group if you exceed maxPollInterval, so a long database call can trigger an endless rebalance loop.
  • Connecting and disconnecting the producer per request. Each cycle is a fresh connection and metadata fetch. Create it once at startup.
  • Assuming Kafka is a task queue. There is no per-message ack, no delayed delivery, and no priority. Those are job queue features, not Kafka features.

💡 The one metric to watch in production

Consumer lag is the number of records published but not yet processed by a group. A steadily rising lag means your consumers cannot keep up, and it is the earliest warning you will get. Check it with kafka-consumer-groups.sh --describe --group <your-group>.

Frequently Asked Questions

What is the difference between Kafka and RabbitMQ?
TraitKafkaRabbitMQ
Core modelDurable log consumers read fromBroker that routes and deletes messages
After a message is readStays in the log until retention expiresRemoved from the queue on ack
Replay past messagesBuilt in, reset the offsetNot possible without republishing
Per-message ackNo, offsets are committed in batchesYes, ack or nack each message
Delayed or priority deliveryNot supportedSupported
Typical throughputVery high, hundreds of thousands per secondHigh, but lower than Kafka

Choose Kafka when several consumers need the same stream, or when replay and retention matter. Choose RabbitMQ when you are distributing discrete jobs to workers and need per-job acknowledgement, retries, and priorities.

Is Kafka overkill for a small app?

Often yes, and the honest test is whether more than one consumer needs the same event.

  • One background job, one worker: a Redis-backed queue such as BullMQ is simpler and has features Kafka lacks.
  • Several independent reactions to the same event: Kafka starts paying for itself, even inside one app.
  • You need an audit trail or replay: Kafka is a strong fit regardless of your app's size.
  • A managed cluster is not in budget: self-hosting Kafka is real operational work, so weigh that honestly.
Do I still need Zookeeper for Kafka in 2026?

No. KRaft mode replaced Zookeeper for metadata management, and Zookeeper support was removed entirely in Kafka 4.0. The docker-compose.yml in this guide runs Kafka with no Zookeeper container at all.

ℹ Info

If a tutorial tells you to run a zookeeper service alongside Kafka, it predates Kafka 3.3 and its other advice is probably out of date too.

Can I use Kafka with TypeScript?

Yes. KafkaJS ships its own type definitions, so no @types package is needed. The one thing worth adding yourself is typing the decoded payload, because message.value is a Buffer and Kafka knows nothing about your event shape.

typescript — consumer.ts
import { Kafka, type EachMessagePayload } from "kafkajs";

interface OrderPlaced {
  id: string;
  item: string;
  total: number;
}

const kafka = new Kafka({ clientId: "email-service", brokers: ["localhost:9092"] });
const consumer = kafka.consumer({ groupId: "email-service-group" });

await consumer.run({
  eachMessage: async ({ message }: EachMessagePayload) => {
    if (!message.value) return;
    const order = JSON.parse(message.value.toString()) as OrderPlaced;
    console.log(order.id);
  },
});

⚠ Warning

That as OrderPlaced is an assertion, not a check. For anything user-facing, validate the parsed object with Zod or Valibot so a malformed producer cannot crash your consumer.

Which Node.js Kafka client should I use?
  • `kafkajs`: pure JavaScript, no native build, actively maintained, best docs. Correct default for almost every project.
  • `node-rdkafka`: binds to librdkafka, higher throughput, but native compilation complicates Docker images and CI.
  • `@confluentinc/kafka-javascript`: Confluent's official client, API-compatible with KafkaJS, worth evaluating if you are on Confluent Cloud.
  • `kafka-node`: effectively unmaintained. Avoid for new work.

Start with kafkajs and move only if you have measured a throughput ceiling you can attribute to the client rather than your own handler code.

Does Kafka guarantee each message is processed exactly once?

Not by default, and not in the way most people hope. Kafka's default is at-least-once delivery: if a consumer crashes after handling a record but before committing its offset, it will see that record again on restart.

Kafka does support exactly-once semantics through transactions, but only for reads and writes that stay inside Kafka. The moment your handler sends an email or charges a card, that side effect is outside the transaction.

  1. Make handlers idempotent: derive a deterministic ID from the record and check it before acting.
  2. Store the processed ID with the write: in the same database transaction as the work itself, so a replay is a no-op.
  3. Treat duplicates as normal: design for them rather than trying to configure them away.
How long does Kafka keep messages?

Seven days by default, controlled per topic by retention.ms, and independent of whether anyone has read them. Kafka deletes on age or size, never on consumption.

bash
docker exec -it kafka /opt/kafka/bin/kafka-configs.sh \
  --bootstrap-server localhost:9092 \
  --entity-type topics --entity-name order-placed \
  --alter --add-config retention.ms=2592000000

That sets 30 days. For event sourcing you may want retention.ms=-1 for unlimited retention, or log compaction, which keeps only the latest record per key instead of deleting by age.

Can I connect to Kafka from a serverless function or edge runtime?

Not with KafkaJS. The Kafka protocol runs over raw TCP with long-lived connections, and edge runtimes such as Cloudflare Workers and Vercel Edge expose only fetch. Short-lived serverless functions can technically connect, but paying the connection and metadata handshake on every invocation makes it impractical.

  • Producing from the edge: use a REST proxy such as Confluent's REST Proxy, or a managed HTTP-first broker like Upstash Kafka.
  • Consuming: run consumers as long-lived processes on a container platform, never in a function with an execution timeout.
  • Hybrid setup: have the edge write to an HTTP endpoint on a long-running service, and let that service own the Kafka connection.

Kafka is smaller than its reputation. Strip away the vocabulary and it is an append-only log that remembers what happened, plus a rule about who reads which part of it. Producers, consumers, topics, partitions, and consumer groups are all just consequences of that one idea.

The practical path is to run the docker-compose.yml above, get the producer and consumer talking, then start a second consumer and watch the partitions rebalance. Those twenty minutes teach you more than any diagram.

After that, resist the pull toward microservices. Publish your first real events inside the app you already have, get comfortable with ordering, offsets, and lag where a single stack trace still explains everything, and let genuine scaling pressure (not architecture fashion) decide when it is time to split things apart.

Written by

Zeeshan Tofiq, Full Stack Developer
Zeeshan Tofiq

Full Stack Developer

Full stack developer with over 6 years of experience building production applications. Writes practical guides on JavaScript, TypeScript, React, Node.js, and cloud infrastructure. Focused on helping developers solve real problems with clean, maintainable code.

All articles by Zeeshan TofiqGitHubLinkedIn

Enjoyed this article?

Get practical dev guides, tool updates, and new articles delivered straight to your inbox. No spam, unsubscribe anytime.

Related Articles

nodejs

Node.js Microservices Without Express: A Zero-Dependency Guide

Build two real Node.js microservices with zero npm installs, using node:http, fetch, and node:test. No Express, no Docker required.

Sep 11, 2026·19 min read
nodejs

30 NestJS Interview Questions and Answers (2026)

30 NestJS interview questions with full answers: modules, DI, guards, pipes, interceptors, JWT auth, microservices, and testing. Updated for 2026.

Jun 8, 2026·31 min read
databases

Redis Explained: What It Is & How to Use It With Node.js

Confused about what Redis actually is? This guide explains Redis in plain English, then shows how to set it up with Docker and use it with Node.js caching.

Sep 28, 2026·13 min read

On this page

  • What Kafka Actually Solves
  • The Core Concepts, One Example Throughout
  • What You Would Actually Use Kafka For
  • Running Kafka Locally With Docker and Node.js
  • Making the Producer Actually Reliable
  • Consumer Groups and Scaling, In Practice
  • Monolith or Microservices? Where Kafka Fits
  • Common Mistakes That Cost People Messages
  • Frequently Asked Questions