Background Jobs With BullMQ

Push Slow Work Off the Request Path

Background Jobs With BullMQ

BullMQ plus @nestjs/bullmq give you Redis-backed job queues with retries, delays, priorities, and a clean DI-friendly API.

5 min read Level 3/5 #nestjs#queues#bullmq
What you'll learn
  • Register BullModule.forRoot with a Redis connection
  • Inject Queue and add jobs from a service
  • Implement a Processor with WorkerHost

Anything that takes longer than a few hundred milliseconds should not run inside an HTTP handler. BullMQ is the modern Redis-backed queue everyone in the Node ecosystem reaches for, and @nestjs/bullmq wraps it in DI.

Install & Configure

npm i @nestjs/bullmq bullmq
import { BullModule } from '@nestjs/bullmq';

@Module({
  imports: [
    BullModule.forRoot({
      connection: {
        host: process.env.REDIS_HOST ?? 'localhost',
        port: Number(process.env.REDIS_PORT ?? 6379),
      },
    }),
    BullModule.registerQueue({ name: 'emails' }),
  ],
})
export class AppModule {}

Enqueue A Job

import { InjectQueue } from '@nestjs/bullmq';
import { Injectable } from '@nestjs/common';
import { Queue } from 'bullmq';

@Injectable()
export class EmailsService {
  constructor(@InjectQueue('emails') private queue: Queue) {}

  async sendWelcome(to: string) {
    await this.queue.add(
      'welcome',
      { to },
      { attempts: 3, backoff: { type: 'exponential', delay: 1_000 } },
    );
  }
}

Jobs return immediately — Redis takes ownership and a worker picks them up.

Process Jobs

import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Job } from 'bullmq';

@Processor('emails')
export class EmailsProcessor extends WorkerHost {
  async process(job: Job<{ to: string }>) {
    if (job.name === 'welcome') {
      await sendMail(job.data.to, 'Welcome!');
    }
  }
}

BullMQ handles retries, backoff, and concurrency for you. Register the processor in any module that imports the emails queue.

Delays, Priorities & Repeats

await this.queue.add('reminder', { id }, { delay: 60_000 });
await this.queue.add('urgent', { id }, { priority: 1 });
await this.queue.add(
  'daily-report',
  {},
  { repeat: { pattern: '0 9 * * *' } },
);

For most teams, BullMQ is the only queue you will ever need.

Scheduled Tasks →