DEV Community

Alex Spinov
Alex Spinov

Posted on

BullMQ Has a Free Job Queue for Node.js — Here's How to Use It

Processing emails, resizing images, or scraping data synchronously blocks your API. BullMQ gives you reliable background jobs with retries, priorities, rate limiting, and a dashboard — all backed by Redis.

What Is BullMQ?

BullMQ is a Node.js message queue and job scheduling library built on Redis. It handles background processing, delayed jobs, rate limiting, and job dependencies.

Quick Start

npm install bullmq
Enter fullscreen mode Exit fullscreen mode
import { Queue, Worker } from 'bullmq';

// Create a queue
const emailQueue = new Queue('emails', {
  connection: { host: 'localhost', port: 6379 }
});

// Add jobs
await emailQueue.add('welcome', {
  to: 'user@example.com',
  subject: 'Welcome!',
  template: 'welcome',
});

// Process jobs
const worker = new Worker('emails', async (job) => {
  console.log(`Sending ${job.data.subject} to ${job.data.to}`);
  await sendEmail(job.data);
}, {
  connection: { host: 'localhost', port: 6379 }
});

worker.on('completed', (job) => console.log(`Job ${job.id} completed`));
worker.on('failed', (job, err) => console.log(`Job ${job.id} failed: ${err}`));
Enter fullscreen mode Exit fullscreen mode

Key Features

Retries with Backoff

await queue.add('process', data, {
  attempts: 5,
  backoff: {
    type: 'exponential',
    delay: 1000, // 1s, 2s, 4s, 8s, 16s
  },
});
Enter fullscreen mode Exit fullscreen mode

Delayed Jobs

// Process in 30 minutes
await queue.add('reminder', data, {
  delay: 30 * 60 * 1000,
});
Enter fullscreen mode Exit fullscreen mode

Cron/Repeatable Jobs

await queue.add('daily-report', data, {
  repeat: {
    pattern: '0 9 * * *', // Every day at 9 AM
  },
});
Enter fullscreen mode Exit fullscreen mode

Rate Limiting

const worker = new Worker('api-calls', processor, {
  limiter: {
    max: 100,       // Max 100 jobs
    duration: 60000, // Per minute
  },
});
Enter fullscreen mode Exit fullscreen mode

Job Priority

await queue.add('task', urgentData, { priority: 1 }); // High
await queue.add('task', normalData, { priority: 5 }); // Normal
await queue.add('task', lowData, { priority: 10 });    // Low
Enter fullscreen mode Exit fullscreen mode

Job Progress

const worker = new Worker('upload', async (job) => {
  for (let i = 0; i < 100; i++) {
    await processChunk(i);
    await job.updateProgress(i + 1);
  }
});

// Listen for progress
const job = await queue.add('upload', data);
job.on('progress', (progress) => console.log(`${progress}%`));
Enter fullscreen mode Exit fullscreen mode

Dashboard (Bull Board)

import { createBullBoard } from '@bull-board/api';
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
import { ExpressAdapter } from '@bull-board/express';

const serverAdapter = new ExpressAdapter();
createBullBoard({
  queues: [new BullMQAdapter(emailQueue), new BullMQAdapter(uploadQueue)],
  serverAdapter,
});

app.use('/admin/queues', serverAdapter.getRouter());
Enter fullscreen mode Exit fullscreen mode

Why BullMQ

Feature BullMQ Celery SQS
Language Node.js Python Any
Backend Redis Redis/RabbitMQ AWS
Dashboard Bull Board Flower Console
Rate limiting Built-in Plugin Manual
Priorities Yes Yes Limited
Cost Free + Redis Free Per-message

Get Started


Processing scraped data in the background? My Apify actors handle parallel data extraction. Custom solutions: spinov001@gmail.com

Top comments (0)