Stop 15 · Message Queues & Event-Driven ArchitectureTopics · 4/8

BullMQ

Part of the Backend Developer Roadmap

In short

Already using Redis? BullMQ turns it into a full job queue for Node, with retries, delays, priorities and scheduled jobs, in a few lines of TypeScript.

A popular Redis-backed job/message queue library for Node.js — simpler to set up than RabbitMQ or Kafka, and a common first choice for background jobs in a Node backend.

The blob in a chef hat pulls an order slip off a metal ticket rail above the stove.

Think of it like this

The restaurant ticket rail

The waiter clips each order slip on the rail above the stove. Cooks pull slips in order, and if a dish burns, the slip goes back up to try again. A slip marked 'serve at 8' waits its turn. BullMQ is that rail, with Redis holding the slips.

Watch it happen

A job with retries

API
Redis
Worker

add welcome, attempts 3

1/5The API adds a job to the emails queue. BullMQ stores it in Redis as waiting.

The big ideas

What you need to know

Retries with backoff

Set attempts and backoff per job. Temporary failures heal on their own without you writing retry loops.

Delayed and scheduled jobs

Add a delay for 'remind in 1 hour', or set up repeating jobs for daily reports.

Concurrency

One worker can run several jobs at once with the concurrency option. Run more worker processes to scale further.

Redis is the store

Jobs live in Redis. Use a persistent Redis setup, or a crash can lose waiting jobs.

See it in code

Walk through the code

ts
1import { Queue, Worker } from "bullmq";2 3const connection = { host: "localhost", port: 6379 };4export const emailQueue = new Queue("emails", { connection });5 6await emailQueue.add("welcome", { userId: 7 }, {7  attempts: 3,8  backoff: { type: "exponential", delay: 1000 },9});10 11new Worker("emails", async (job) => {12  await sendWelcomeEmail(job.data.userId);13}, { connection, concurrency: 5 });

1/3A queue is a name plus a Redis connection. Producers and workers use the same name.

Run the Worker in a separate process from your API, so heavy jobs never slow down requests. Throwing inside the processor marks the job failed.

Save yourself the pain

Common mistakes

Oops

Putting a 5 MB PDF inside job data.

Do this instead

Store files in S3 or disk and put only the key or id in the job. Redis memory is precious.

Oops

Running Redis with an eviction policy like allkeys-lru for BullMQ.

Do this instead

Use noeviction, or Redis may silently delete your jobs when memory fills up.

Your mission

A flaky job that heals

~30 min

Quick check

Your API and BullMQ worker run in the same process, and a CPU-heavy job slows every request. What's the usual fix?

Go deeper

  1. 1Set up a BullMQ queue and worker to process a background job, e.g. sending an email.
  2. 2Add retry logic with exponential backoff for failed jobs.
  3. 3Use BullMQ's dashboard (Bull Board) to monitor job status.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge