BullMQ and Redis basics

BullMQ is the standard Node library for Redis-backed queues. You create a Queue object with a name, then producers call add to enqueue jobs and consumers pull jobs off it to process. That is the entire mental model.

after/queue.ts
typescript
import { Queue, ConnectionOptions } from 'bullmq';

let _connectionOpts: ConnectionOptions | null = null;
let _orderQueue: Queue | null = null;

export function getRedisConnectionOpts(): ConnectionOptions {
  if (!_connectionOpts) {
    const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379';
    const url = new URL(REDIS_URL);
    _connectionOpts = {
      host: url.hostname,
      port: parseInt(url.port, 10),
      // Required for BullMQ workers that use blocking Redis commands
      maxRetriesPerRequest: null,
      enableOfflineQueue: false,
    };
  }
  return _connectionOpts;
}

export function getOrderQueue(): Queue {
  if (!_orderQueue) {
    _orderQueue = new Queue('OrderConfirmations', {
      connection: getRedisConnectionOpts(),
    });
  }
  return _orderQueue;
}

Lazy initialization of the Redis connection and the OrderConfirmations queue.

Notice that neither the connection nor the queue is built at import time. They are created on first use. This matters for tests: they can point REDIS_URL at a different Redis or disable it entirely before any connection is attempted. Lazy initialization is a small habit that pays off in every test suite you ever write.

One gotcha worth calling out: maxRetriesPerRequest must be null for BullMQ workers. BullMQ uses blocking Redis commands that wait indefinitely for new jobs. Setting a retry limit makes Redis report the blocked connection as dead and the worker panics. null disables the retry cap, which is what BullMQ needs.

Quiz: Quiz

Loading practice…