# Ack & Reject (/sdks/nodejs/how-to/queues/ack-reject)



## Overview [#overview]

Ack and reject give you per-message control over queue delivery instead of an all-or-nothing batch outcome. When `receiveQueueMessages()` fetches a batch, each message stays locked on the broker — invisible to other consumers — until the consumer explicitly settles it. That's what you need when one bad record in a batch shouldn't take the rest down with it.

Settlement happens through two calls on the received message: `msg.ack()`, which permanently removes it from the queue, and `msg.nack()`, which returns it to the queue for redelivery (or routes it to the dead-letter queue if `maxReceiveQueue` is configured). Internally the broker tracks this against a receive count, which a dead-letter policy can use to stop retrying a poison message forever.

**Gotchas:** an unsettled message isn't gone — it snaps back to the queue once the visibility timeout expires, so a slow consumer looks identical to a rejecting one; settle every message before that deadline, and never assume a batch is fully processed until you've called `ack()` or `nack()` on each one individually.

## Prerequisites [#prerequisites]

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

## Code [#code]

```typescript title="ack-reject.ts"
/**
 * Example: Message Acknowledgment and Rejection
 *
 * Demonstrates the two message handling options after receiving a queue
 * message via simple receive: acknowledge (success) or reject (send to
 * dead-letter queue).
 *
 * Prerequisites:
 *   - KubeMQ server running on localhost:50000
 *
 * Run: npx tsx examples/queues/ack-reject.ts
 */
import { KubeMQClient, createQueueMessage } from 'kubemq-js';

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

  try {
    // Send test messages with different intents.
    for (const task of ['valid-task', 'bad-format', 'another-valid-task']) {
      await client.sendQueueMessage(
        createQueueMessage({
          channel: 'js-queues.ack-reject',
          body: task,
          tags: { type: task },
        }),
      );
    }

    const messages = await client.receiveQueueMessages({
      channel: 'js-queues.ack-reject',
      waitTimeoutSeconds: 5,
      maxMessages: 10,
    });

    for (const msg of messages) {
      const body = new TextDecoder().decode(msg.body);

      if (body === 'bad-format') {
        // Permanently reject — message goes to dead-letter queue if configured.
        await msg.nack();
        console.log('Rejected:', body);
      } else {
        // Acknowledge successful processing.
        await msg.ack();
        console.log('Acknowledged:', body);
      }
    }
  } finally {
    await client.close();
  }
}

main().catch(console.error);

```

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

* `receiveQueueMessages()` with `maxMessages: 10` fetches up to 10 messages in a single poll and locks them for processing.
* `await msg.ack()` marks the message as successfully processed — it is permanently removed from the queue.
* `await msg.nack()` permanently rejects the message: if `maxReceiveQueue` is configured on the message policy the message moves to the dead-letter queue; otherwise it is discarded.
* Each ack/nack must be called before the visibility timeout expires; the `waitTimeoutSeconds` on the receive controls how long the server waits for a consumer, not the ack deadline.

## Related [#related]

* [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)
