# Dead Letter Queue (/sdks/nodejs/how-to/queues/dead-letter-queue)



<Callout type="info" title="Which to use">
  This page is the task-oriented walkthrough: send a message with DLQ routing configured, let it exhaust retries, and consume the diverted message. For the `policy` field reference — `maxReceiveCount`/`maxReceiveQueue` defaults and edge cases — see [Dead Letter Policy](./dead-letter-policy).
</Callout>

## Overview [#overview]

A &#x2A;*dead-letter queue (DLQ)** gives a poison message somewhere to go instead of looping through consumers forever. When a message keeps failing — a malformed payload, a downstream outage, a handler bug — retrying it forever wastes consumer cycles and blocks everything behind it. A DLQ takes that decision out of your hands: past a set number of failed attempts, the broker diverts the message to a separate channel instead of retrying it again.

Routing runs on two `policy` fields passed to `createQueueMessage()`: `maxReceiveCount` and `maxReceiveQueue`. Every failed delivery — a missing `ack()`, a reject, or an expired visibility window — increments `receiveCount`; past the threshold, the broker reroutes the message to the DLQ instead of redelivering it. The DLQ itself is an ordinary queue, consumed like any other channel.

**Gotchas:** the DLQ doesn't drain itself — a dedicated consumer must watch it. The count increments on *any* failed delivery, not just deliberate rejections — a slow consumer that lets the visibility window lapse counts the same as an explicit nack. A typo in the DLQ channel name quietly creates an unrelated channel instead of failing loudly.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* Node.js SDK installed (`npm install kubemq-js`)

## Code [#code]

```typescript title="dead-letter-queue.ts"
/**
 * Example: Dead-Letter Queue with maxReceiveCount
 *
 * Demonstrates configuring messages to automatically move to a dead-letter
 * queue after a specified number of delivery attempts. This prevents poison
 * messages from blocking the queue.
 *
 * Prerequisites:
 *   - KubeMQ server running on localhost:50000
 *
 * Run: npx tsx examples/queues/dead-letter-queue.ts
 */
import { KubeMQClient, createQueueMessage } from 'kubemq-js';

async function main(): Promise<void> {
  const client = await KubeMQClient.create({
    address: 'localhost:50000',
    clientId: 'js-queues-dead-letter-queue-client',
  });

  try {
    // Send a message with a dead-letter policy: after 3 failed deliveries,
    // automatically move to the dead-letter queue.
    await client.sendQueueMessage(
      createQueueMessage({
        channel: 'js-queues.dead-letter-queue',
        body: 'Order #5001: ship to warehouse B',
        policy: {
          maxReceiveCount: 3,
          maxReceiveQueue: 'js-queues.dead-letter-queue-dlq',
        },
      }),
    );
    console.log('Sent message with DLQ policy (max 3 attempts)');

    // Simulate processing failure — receive but don't ack.
    // After visibility timeout, the message becomes available again.
    // After 3 total receives, it moves to 'js-queues.dead-letter-queue-dlq'.
    const messages = await client.receiveQueueMessages({
      channel: 'js-queues.dead-letter-queue',
      waitTimeoutSeconds: 5,
    });

    for (const msg of messages) {
      console.log('Received (attempt #%d):', msg.receiveCount, new TextDecoder().decode(msg.body));
      // Intentionally not acking — simulating a processing failure.
    }
  } finally {
    await client.close();
  }
}

main().catch(console.error);

```

## How It Works [#how-it-works]

* The `policy` field in `createQueueMessage()` attaches a delivery policy: `maxReceiveCount: 3` caps attempts and `maxReceiveQueue` names the dead-letter channel.
* Intentionally not calling `msg.ack()` simulates a processing failure; after the visibility timeout the server makes the message available for re-delivery.
* After the third failed attempt, the server automatically moves the message to `js-queues.dead-letter-queue-dlq` — the consumer never has to implement the DLQ routing logic.
* `msg.receiveCount` increments on each delivery attempt; inspect it to determine how many times a message has been retried before deciding whether to process or reject it.

## Related [#related]

* [Dead Letter Policy](./dead-letter-policy) — field-level reference for `maxReceiveCount` and `maxReceiveQueue`
* [Pattern overview](/learn/queues/getting-started)
* [Node.js SDK Reference](/sdks/nodejs/reference)
* [Send & Receive](/sdks/nodejs/tutorials/send-receive)
* [Ack All](/sdks/nodejs/how-to/queues/ack-all)
