Skip to main content

providers

Providers

  • Balda.js Queue supports the following providers out of the box:

    • BullMQ
    • SQS
    • PgBoss
  • You must also install the corresponding package for each provider:

    • BullMQ: npm install bullmq ioredis
    • SQS: npm install @aws-sdk/client-sqs sqs-consumer
    • PgBoss: npm install pg-boss pg
  • It's also possible to support custom providers via a small PubSub interface.

Single entrypoint configuration

Use defineQueueConfiguration to configure all providers in one place during app bootstrap:

import { defineQueueConfiguration } from 'balda-js';

defineQueueConfiguration({
bullmq: {
connection: { host: '127.0.0.1', username: 'default', password: 'root', db: 0 },
defaultJobOptions: { removeOnComplete: 100, removeOnFail: 100 },
},
sqs: {
client: { region: 'us-east-1' },
consumer: {
queueUrlMap: { test: 'http://localhost:9324/queue/balda-js-development-test' },
batchSize: 10,
},
},
pgboss: {
connectionString: process.env.DATABASE_URL!,
},
});

BullMQ consumer example:

import { queue } from 'balda-js';

export class BullMQHandler {
@queue.bullmq('test')
async handle(payload: { name: string }) {}
}

SQS consumer example:

import { queue } from 'balda-js';

export class SQSHandler {
@queue.sqs('test')
async handle(payload: { name: string }) {}
}

Publish with SQS options when needed:

import { publish } from 'src/queue/pub';

await publish.sqs('test', { name: 'Ada' }, {
// SQS publish options
});

Note: Ensure your queueUrlMap maps each topic to its SQS queue URL.

PgBoss consumer example:

import { queue } from 'balda-js';

export class PGBossHandler {
@queue.pgboss('test')
async handle(payload: { name: string }) {}
}

Publish with PgBoss options when needed:

import { publish } from 'src/queue/pub';

await publish.pgboss('test', { name: 'Ada' }, {
// PGBoss publish options
});

Note: PgBoss automatically creates queues when needed. Ensure your PostgreSQL database is accessible and the pg-boss package is installed.

Custom provider

Implement the PubSub interface and register it via the single entrypoint. For type‑safe usage across your codebase, augment the module types:

import { defineQueueConfiguration } from 'balda-js';
import type { PubSub, QueueTopic, QueueTopicKey } from 'balda-js';

class CustomPubSub implements PubSub<'custom'> {
async publish<T extends QueueTopicKey>(topic: T, payload: QueueTopic[T]) {
return { id: '1' };
}

async subscribe<T extends QueueTopicKey>(topic: T, handler: (payload: QueueTopic[T]) => Promise<void>) {
// wire your consumer and call handler(payload)
}
}

declare module 'balda-js' {
interface QueueProvider {
custom: PubSub<'custom'>;
}
}

defineQueueConfiguration({
// Custom provider is avaliable after the type augmentation
custom: new CustomPubSub(),
});

Then decorate consumers and publish as usual using the provider key.

You can also register handlers without decorators using the static service:

import { QueueService } from 'balda-js';

// Decorators are just a shortcut for this
QueueService.register(
'CustomPlainHandler.handle',
'test',
async (payload: { name: string }) => {
// ...
},
{ provider: 'custom' }
);

// Ensure this file is imported before starting subscribers