Skip to main content
npayload is launching soon.
npayloadDocs
Guides

Publishing messages

Single, batch, and transactional publish with message groups, idempotency, routing keys, and priorities

Publishing is the core operation in npayload. You send a message to a channel and npayload delivers it to all matching subscriptions. This guide covers every publishing pattern available.

Single publish

The simplest operation: publish one message to one channel.

import { NPayloadAuth, NPayloadClient } from '@npayload/node';

const auth = new NPayloadAuth({
  clientId: process.env.NPAYLOAD_CLIENT_ID!,
  hmacSecret: process.env.NPAYLOAD_HMAC_SECRET!,
});
const npayload = new NPayloadClient({ auth });

await npayload.messages.publish('orders', {
  payload: {
    event: 'order.created',
    orderId: 'ord_12345',
    total: 59.98,
  },
});

The response includes the message GID, which you can use to track delivery status.

const result = await npayload.messages.publish('orders', {
  payload: { event: 'order.created', orderId: 'ord_12345' },
});

console.log(result.messageGid); // "msg_abc123"

Batch publish

Publish up to 100 messages in a single request. All messages go to the same channel.

const messages = orders.map((order) => ({
  payload: {
    event: 'order.created',
    orderId: order.id,
    total: order.total,
  },
}));

const result = await npayload.messages.publishBatch('orders', messages);
console.log(result.published); // number of messages published

Batch publish is not atomic. If some messages fail validation, the valid ones are still published. Check the response for per-message status.

Transactional publish

Publish messages to multiple channels atomically. Either all messages are published or none are. This is useful when a single business event needs to update several channels.

await npayload.messages.publishTransactional([
  {
    channel: 'orders',
    payload: { event: 'order.created', orderId: 'ord_12345' },
  },
  {
    channel: 'inventory',
    payload: { event: 'stock.reserved', sku: 'WIDGET-A', quantity: 2 },
  },
  {
    channel: 'notifications',
    payload: { event: 'notify.customer', email: 'buyer@example.com' },
  },
]);

Transactional publish supports up to 10 channel targets per transaction. All messages are committed together or rolled back on failure.

Message groups (FIFO ordering)

By default, npayload delivers messages in parallel for maximum throughput. When you need strict ordering, use message groups. Messages in the same group are delivered sequentially, in the order they were published.

// All messages for the same order are delivered in order
await npayload.messages.publish('orders', {
  payload: { event: 'order.created', orderId: 'ord_12345' },
  groupKey: 'ord_12345',
});

await npayload.messages.publish('orders', {
  payload: { event: 'order.paid', orderId: 'ord_12345' },
  groupKey: 'ord_12345',
});

await npayload.messages.publish('orders', {
  payload: { event: 'order.shipped', orderId: 'ord_12345' },
  groupKey: 'ord_12345',
});

Different group keys are processed independently. Ordering is guaranteed only within the same group.

Idempotency keys

Prevent duplicate messages when retrying failed requests. If you publish with the same idempotency key within 24 hours, npayload returns the original result without creating a duplicate.

await npayload.messages.publish('orders', {
  payload: { event: 'order.created', orderId: 'ord_12345' },
  idempotencyKey: 'create-ord_12345',
});

// Safe to retry: same key returns the same result
await npayload.messages.publish('orders', {
  payload: { event: 'order.created', orderId: 'ord_12345' },
  idempotencyKey: 'create-ord_12345',
});

Idempotency keys are scoped to your organisation and app. They expire after 24 hours.

Routing keys

Attach a routing key to a message so that subscribers can filter by pattern. Only subscriptions with a matching routing key filter receive the message.

await npayload.messages.publish('events', {
  payload: { event: 'user.signup', region: 'eu-west' },
  routingKey: 'user.signup.eu-west',
});

await npayload.messages.publish('events', {
  payload: { event: 'user.signup', region: 'us-east' },
  routingKey: 'user.signup.us-east',
});

Subscribers use glob patterns to match routing keys. See Subscriptions and delivery for filter syntax.

Priority messages

When publishing to a priority channel, assign a priority level from 0 (lowest) to 9 (highest). Higher priority messages are delivered first.

// Critical alert: priority 9
await npayload.messages.publish('alerts', {
  payload: { level: 'critical', message: 'Database connection pool exhausted' },
  priority: 9,
});

// Informational: priority 1
await npayload.messages.publish('alerts', {
  payload: { level: 'info', message: 'Deployment completed successfully' },
  priority: 1,
});

Priority only applies to channels created with type: 'priority'. See Working with channels for setup.

Report messages (receipt confirmation)

Request a delivery receipt from consumers. When a subscriber processes the message and sends back a report, you receive confirmation that processing completed.

const result = await npayload.messages.publish('tasks', {
  payload: { task: 'generate-report', reportId: 'rpt_001' },
  reportRequested: true,
});

// Later, check for reports
const reports = await npayload.messages.getReports(result.messageGid);
for (const report of reports) {
  console.log(`Subscriber ${report.subscriberGid} reported: ${report.status}`);
}

Subscribers send reports using the SDK:

await npayload.messages.report(messageGid, {
  status: 'processed',
  details: { rowsGenerated: 1520 },
});

Payload limits and best practices

LimitValue
Max payload size256 KB
Max batch size100 messages
Max transactional targets10 channels
Idempotency key TTL24 hours
Routing key max length256 characters

Best practices:

  • Use idempotency keys for any publish that might be retried (network errors, timeouts)
  • Use message groups only when ordering matters. Ungrouped messages have higher throughput
  • Keep payloads small. Store large data externally and publish a reference (URL or ID)
  • Use routing keys to reduce unnecessary deliveries rather than filtering on the consumer side
  • Use transactional publish when consistency across channels is required

Next steps

Was this page helpful?

On this page