# Delayed Messages (/sdks/nodejs/how-to/queues/delayed-messages)



<Callout type="info" title="Which to use">
  This is the task-oriented guide for sending delayed messages. For the `policy: { delaySeconds }` delay-policy option reference, see [Delay Policy](./delay-policy).
</Callout>

## Overview [#overview]

Use a **delivery delay** to hold a queue message out of consumers' reach for a fixed window after you send it — the broker accepts and persists the message immediately, but keeps it invisible to pollers until the delay expires. Reach for this when you need scheduled work — a reminder to fire in an hour, a retry with back-off, a task queued for off-peak processing — without standing up a separate scheduler or cron service.

Set it with `policy: { delaySeconds: ... }` when you create the message; the broker does the waiting. Check the send result's `delayedTo` field — it returns a `Date` confirming exactly when the message becomes visible, so you can log or monitor delayed pipelines. Until then, any poll you make via `receiveQueueMessages` against that channel simply returns nothing for that message — it isn't hidden in a separate place, it's the same queue, just not yet eligible for delivery.

**Gotchas:** set the delay once at send time — you can't extend or shorten it afterward, so send a new message if you need a different wait. A long delay still counts as an in-flight, persisted message, so it survives a broker restart, but it also occupies queue storage for the whole waiting period. Don't confuse this with a *visibility timeout* after delivery — that's a separate mechanism for redelivery on failed acknowledgment, not initial availability.

## Prerequisites [#prerequisites]

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

## Code [#code]

```typescript title="delayed-messages.ts"
/**
 * Example: Delayed Message Delivery
 *
 * Demonstrates sending queue messages with a delay. The message is accepted
 * immediately but only becomes visible to consumers after the delay expires.
 * Useful for scheduling future work.
 *
 * Prerequisites:
 *   - KubeMQ server running on localhost:50000
 *
 * Run: npx tsx examples/queues/delayed-messages.ts
 */
import { KubeMQClient, createQueueMessage } from 'kubemq-js';

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

  try {
    // Send a message delayed by 10 seconds.
    const result = await client.sendQueueMessage(
      createQueueMessage({
        channel: 'js-queues.delayed-messages',
        body: 'Send follow-up email to user@example.com',
        policy: {
          delaySeconds: 10,
        },
      }),
    );

    console.log('Sent delayed message:', result.messageId);
    console.log('Message will become visible at:', result.delayedTo?.toISOString());

    // Immediate poll returns nothing — message is still delayed.
    const immediate = await client.receiveQueueMessages({
      channel: 'js-queues.delayed-messages',
      waitTimeoutSeconds: 2,
    });
    console.log('Immediate poll received:', immediate.length, 'messages');

    // Wait for the delay to expire, then poll again.
    console.log('Waiting 11 seconds for delay to expire...');
    await new Promise((resolve) => setTimeout(resolve, 11_000));

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

    for (const msg of delayed) {
      console.log('Received delayed message:', new TextDecoder().decode(msg.body));
      await msg.ack();
    }
  } finally {
    await client.close();
  }
}

main().catch(console.error);

```

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

* `policy: { delaySeconds: 10 }` makes the message invisible to consumers for 10 seconds after it is accepted by the server.
* `result.delayedTo` is a `Date` returned by the server confirming the exact visibility time — useful for logging or scheduling follow-up work.
* The first `receiveQueueMessages()` call with `waitTimeoutSeconds: 2` returns immediately with 0 messages because the delay has not expired yet.
* After 11 seconds the message becomes visible, the second poll picks it up, and `msg.ack()` removes it permanently from the queue.

## Related [#related]

* [Delay Policy](./delay-policy) — field-level reference for `policy: { delaySeconds }`
* [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)
