Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

BullMQ lets Node.js applications hand work off to Redis-backed queues so workers can process jobs outside the request path. A reliable setup depends on separating job production from processing, choosing retry behavior deliberately, and configuring Redis and workers for failure and recovery.

How BullMQ handles background jobs

BullMQ’s core model separates the code that adds work from the code that performs it. A Queue accepts and manages jobs; a Worker consumes them and marks them completed or failed. As the BullMQ introduction puts it, “Jobs are processed by workers.”

The API also includes QueueEvents for queue-wide job events and FlowProducer for creating related jobs with dependencies. Workers can run in the same Node.js process as producers, in separate processes, or on separate machines. Separating workers can isolate processing from request handling and let you scale the two parts independently.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A basic producer and worker

import { Queue, Worker } from 'bullmq';

const connection = { host: '127.0.0.1', port: 6379 };
const queue = new Queue('email', { connection });

await queue.add('send-confirmation', {
  userId: 'user-123',
  template: 'confirmation',
});

const worker = new Worker(
  'email',
  async job => {
    if (job.name === 'send-confirmation') {
      await sendConfirmation(job.data);
    }
  },
  { connection },
);

This illustrates the responsibilities, not a complete application: define sendConfirmation, manage the Redis connection, and close the queue and worker as part of your application lifecycle. See the queue guide and worker guide for the API details.

Choose the backend and connection behavior

Redis is BullMQ’s default backend. The connections guide also documents adapters for ioredis, node-redis, Bun, and Valkey Glide, as well as a PostgreSQL backend. Availability and backend-specific behavior depend on the BullMQ version and adapter; verify compatibility in the documentation for the version you deploy.

Prefer the higher-level Queue and Worker APIs where they meet your needs. Backend-specific escape hatches may not behave identically across supported backends.

Give producers and workers different recovery policies

A producer called during a user request should have bounded failure behavior: if Redis is unavailable, the application should not wait indefinitely to report whether it accepted the job. A worker has a different job. It should be configured to reconnect and resume processing when Redis returns. BullMQ’s production guidance and connection documentation discuss these differing needs.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make failures and retries intentional

If a processor throws an exception, BullMQ marks the job failed. Retrying is not automatic by default: set attempts to more than one and select a backoff policy. Throw an actual JavaScript Error object so failure handling has useful error information.

await queue.add('send-confirmation', data, {
  attempts: 5,
  backoff: {
    type: 'exponential',
    delay: 1000,
  },
});

BullMQ provides fixed and exponential backoff, optional jitter, and custom strategies. With exponential backoff, the documented delay is 2 ^ (attempts - 1) * delay; this describes the configured schedule, not a performance guarantee. Consult the retry guide for supported options and examples.

Match the retry policy to the error

  • Transient errors: A temporary network failure or unavailable dependency may justify another attempt, with a delay that avoids immediately repeating the same failure.
  • Permanent errors: Invalid input or an unsupported operation generally needs a deliberate terminal path, such as recording the failure for correction, rather than spending attempts repeating work that cannot succeed.
  • Side effects: A job can fail after an external service has already acted. Design processors and downstream operations to tolerate a repeated attempt where possible; a retry alone cannot guarantee exactly-once effects.

Decide how operators will identify and investigate exhausted jobs. Retention settings affect how much completed and failed job history remains available, so make those settings part of the same operational design rather than an afterthought.

Configure rate limits for the installed version

BullMQ supports global queue rate limits. A worker-level rate limit does not override a global limit. The rate-limiting guide describes the current API; check it against the BullMQ version in your application before copying configuration from older examples.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Two version changes matter when maintaining older code: group-key rate limiting was removed in BullMQ 3.0, and QueueScheduler is not needed for delayed jobs or rate limiting in BullMQ 2.0 and later, according to the current queue and rate-limit guidance. Older snippets may therefore describe behavior that no longer applies.

Prepare Redis and workers for production

Protect queue data from arbitrary eviction

BullMQ stores queue state in its backend, so Redis memory policy is consequential. Its production guide recommends maxmemory-policy=noeviction; arbitrary key eviction can undermine queue behavior. The guide states: “BullMQ on the other hand cannot work properly if Redis evicts keys arbitrarily.” Configure this deliberately rather than allowing Redis to discard keys under memory pressure.

The production guide also recommends considering Redis AOF persistence and benchmarking its effect for your workload. Persistence choices influence recovery and durability trade-offs; do not assume a setting is free of performance or operational cost.

Handle shutdown and stalled work

Attach error handlers and close workers gracefully when the application receives SIGINT or SIGTERM. Graceful shutdown gives active work a chance to finish and reduces avoidable stalled jobs. Follow the production deployment guide for lifecycle and deployment considerations.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

CPU-intensive processors can block Node.js’s event loop. If the event loop is blocked long enough to prevent lock renewal, BullMQ can mark a job stalled. Keep heavy CPU work from monopolizing the worker event loop, and investigate stalled jobs as a possible symptom of processor design or runtime pressure.

Set retention and protect payloads

Choose how many completed and failed jobs to retain based on the visibility needed for operations and debugging, balanced against Redis storage. Job data is stored in clear text; avoid placing sensitive information in payloads, or encrypt sensitive fields before enqueueing. Apply appropriate access controls to the backend as well.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Observe the job lifecycle

BullMQ’s telemetry interface supports OpenTelemetry and is intended to expose job lifecycle state and interactions. This can complement queue and worker error handling with traces or other instrumentation; choose observability based on the lifecycle visibility and operational signals your team needs. See the telemetry guide.

Production readiness checklist

  • Confirm the BullMQ version and use documentation that matches it, especially for rate limits and scheduler behavior.
  • Choose a documented backend and adapter, and keep backend-specific behavior in mind.
  • Use bounded failure behavior for producers and reconnect behavior for workers.
  • Set Redis persistence intentionally, and benchmark AOF impact for your workload if you enable it.
  • Set Redis maxmemory-policy to noeviction.
  • Configure attempts and backoff around the errors that can realistically recover.
  • Plan for idempotent handling of side effects, retained job history, and sensitive payload fields.
  • Register error handlers and gracefully close workers on SIGINT and SIGTERM.
  • Check whether CPU-heavy processing could block lock renewal, and instrument job lifecycle behavior.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.