Library / SDK
nestjs/bull avatar
nestjs/bull

nestjs/bull: the Nest modules that put Bull and BullMQ queues inside a Nest app

Bull module for Nest framework (node.js) :cow:

704 stars113 forksTypeScriptMIT

At a glance

What is it?
nestjs/bull is a monorepo publishing @nestjs/bull, @nestjs/bullmq and @nestjs/bull-shared, the Nest integration layer for Redis backed job queues. It is the queue answer for teams already on Nest, and it is deliberately thin, since the heavy lifting still belongs to the Bull and BullMQ projects and to your own Redis instance.
Who is it for?
Adopt nestjs/bull when your application is already Nest and you want queues wired into the framework dependency injection and lifecycle rather than hand rolled Redis code, and skip it if you need a queue library that does not depend on Nest.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A monorepo that ships three packages, not one

The repository is described in one line as a monorepo containing Nest modules for Bull and BullMQ, and the published artifacts reflect that split. Three packages carry version 12.0.0 releases dated 2026-08-27: @nestjs/bull, @nestjs/bullmq and @nestjs/bull-shared. The shared package is the piece that makes the split workable, since the two queue backends expose similar concepts and the shared code is where that common ground lives.

The repository root explains how it is built. The package.json is a private workspace manifest named @nestjs/bull-workspace with yarn workspaces covering packages/*, and lerna.json sits alongside it. The build script runs tsc -b -v packages, so the packages are compiled as a TypeScript project graph rather than one bundle. The publish path runs lerna publish, and the next tagged flow publishes with the next dist tag. Yarn.lock at the root and renovate.json for dependency updates complete the picture of a conventional monorepo with automated dependency bumps.

This shape has a practical consequence for a consumer. You do not install a single bull package. You choose between two integration packages, and depending on which one you pick, the shared package comes along as its dependency.

Two install paths, and they are not interchangeable

The installation section is deliberately split into two commands, one per backend. For the classic Bull queue:

bash
$ npm i --save @nestjs/bull bull

And for BullMQ:

bash
$ npm i --save @nestjs/bullmq bullmq

Both lines install two packages, not one, and the reason is visible in the naming. The @nestjs prefixed package is the Nest integration layer, and the second package is the underlying queue library itself, from OptimalBits for Bull and from taskforcesh for BullMQ. The Nest module does not replace the queue library; it wraps it.

The repository does not explain the functional differences between the two backends, and that is worth stating plainly rather than filling the gap with general knowledge. The documentation points to the queues overview and tutorial at docs.nestjs.com, and that is where the choice between them is meant to be settled. What this repository is responsible for is the Nest side: the module, the processors, and the injection points.

The other consequence of a wrapper is that the queue semantics you inherit are the upstream project's semantics. Retries, concurrency, priorities and job removal policies are configured on the Bull or BullMQ objects, not on the Nest module, so reading the upstream documentation is unavoidable.

The development Redis is published on the wrong port for the default

The repository ships a single docker-compose.yml with one service, Redis. It is a development convenience rather than a deployment artefact, and it contains a detail that trips people up:

yaml
version: "3"
services:
  redis:
    image: redis:alpine
    ports:
      - 6380:6379

The mapping is host port 6380 to container port 6379, which is the standard Redis port inside the container. So the compose file gives you a Redis listening on 6379 inside the container network, reachable from the host only on 6380. A Nest application running on the host, which is the normal arrangement while developing against this compose file, therefore needs a connection string pointing at 6380.

If you instead point the application at the well known 6379 on the host, nothing in the compose file is listening there, and the symptom is a consumer that starts cleanly and never receives a job. That is the failure mode to check first, and it is the one that most often sends people looking at their processor decorators rather than at their port.

The image is redis:alpine, so the container is small. Nothing in the compose file sets a password, a persistence volume, or a memory limit, which is consistent with a throwaway development database rather than a production topology.

Processors are instrumented automatically by NestJS Observe

The observability section describes something that is unusual for a queue wrapper: queue consumers are instrumented automatically by NestJS Observe, the official observability platform for Nest. No manual tracing setup is described for the consumer path. Classes marked with @Processor and their handlers are reported as jobs, and the reported dimensions are duration, outcome, queue wait time and retry attempts.

The failure path carries more detail than a simple error count. A failed run carries the resolved stack trace, the logs written during it, and the waterfall of what the job did before it threw. That last part matters in practice, because a job that throws halfway through often leaves partial side effects, and knowing the sequence of steps before the exception narrows down which one broke.

There is also a silence alert. It fires when a named job stops reporting, which catches the failure that dashboards usually miss, a worker that has died or a queue that has gone quiet while every dashboard still shows green. The documentation points to the Observability chapter and to the queues chapter for what the setup looks like.

The honest caveat is that this capability belongs to the Observe platform rather than to the queue modules themselves. What the modules contribute is the ability to be instrumented, since the processor and handler structure is what carries the job boundaries. Whether you can use it depends on your access to that platform.

The monorepo toolchain that produces the packages

The package.json documents the development workflow in full, which tells you what it costs to work on this project or to match its conventions in your own code. Formatting runs through prettier with a project config, linting runs oxlint with oxlint.json, and commit messages are checked by commitlint against the Angular config, wired in through husky as a prepare hook and lint-staged on staged files. The type script sorts package.json through sort-package-json.

Testing has four entry points, all run through lerna across packages in parallel: test, test:dev, test:e2e and test:e2e:dev. The unit tests run on vitest, and the TypeScript in use is 7.0.2. The continuous integration configuration lives under .circleci, and CONTRIBUTING.md is present at the root.

For a consumer, none of this needs to be installed. It matters for two other reasons. First, the quality of the wrapper is bounded by the checks above, and there is a test suite for the packages themselves. Second, a version bump for you means bumping the Nest module version, and the release history is visible: @nestjs/bull 12.0.0, @nestjs/bullmq 12.0.0 and @nestjs/bull-shared 12.0.0, all published on 2026-08-27, with the last push to the repository on 2026-10-19.

The licence is MIT, the same terms the rest of the Nest ecosystem uses, and the repository states that Nest is an MIT licensed open source project.

When the Nest wrapper is the wrong layer

The clearest case for not using this repository is that your application is not Nest. The packages are Nest modules, so their value is that they plug into the framework's dependency injection and lifecycle. An application written in plain Express, Fastify, or anything else gets the Bull or BullMQ npm package on its own, and wrapping it in a Nest module buys nothing.

There is a second case, which is a preference rather than a constraint. Using the upstream library directly means you own the wiring: creating the queue instance, connecting it to Redis, handling shutdown, and deciding how jobs reach your business logic. The Nest module handles that wiring for you inside a Nest application, and the trade is that your job handlers become framework bound rather than framework independent. That is a sensible trade inside a Nest codebase and a bad one in a codebase that plans to migrate frameworks later.

A third limitation is the documentation boundary. This repository points to the Nest documentation for the queue tutorial and at the upstream projects for the queue behaviour itself, so a question about retry semantics or concurrency has to be answered by reading two projects rather than one. That is normal for an integration layer, but it means the wrapper is a small part of the total surface you have to learn.

A fourth point is the Redis dependency. Bull and BullMQ both store their state in Redis, so adopting this module means operating a Redis instance in production, whether it is your own or a managed one. The compose file in this repository offers no persistence, no authentication and no sizing guidance, so those decisions sit entirely with whoever runs it.

Editorial conclusion

Adopt nestjs/bull when your application is already Nest and you want queues wired into the framework dependency injection and lifecycle rather than hand rolled Redis code, and skip it if you need a queue library that does not depend on Nest. Verify first that your Redis instance is reachable at the host and port you configure, since the development compose file in this repository publishes Redis on host port 6380 while the container listens on 6379, and that is the first thing to check when a consumer never receives a job.

Frequently asked questions

How do I install the Nest module for Bull queues?

Run npm i --save @nestjs/bull bull to install the @nestjs/bull integration package together with the Bull queue library. The BullMQ equivalent is npm i --save @nestjs/bullmq bullmq.

What port does the Redis service in the nestjs/bull development compose file use?

The compose file maps host port 6380 to container port 6379 with the redis:alpine image. An application running on the host must therefore connect to 6380, because nothing is published on the default 6379 host port.

Does nestjs/bull provide observability for queue jobs?

Queue consumers are instrumented automatically by NestJS Observe. @Processor classes and their handlers are reported as jobs with duration, outcome, queue wait time and retry attempts, and a failed run carries the resolved stack trace and the logs written during it, with a silence alert for jobs that stop reporting.

What is the difference between @nestjs/bull and @nestjs/bullmq?

They are separate packages wrapping two different upstream queue libraries, Bull from OptimalBits and BullMQ from taskforcesh, and you install one or the other. The repository documents both installations but does not compare the backends, so the choice is settled in the Nest queues documentation.

What licence is nestjs/bull released under?

MIT. The repository states that Nest is an MIT licensed open source project, and the workspace package.json carries the same MIT licence identifier.

Official sources

  1. License: MIT
  2. nestjs/bull on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/nestjs-bull.svg)](https://hysenlabs.com/projects/nestjs-bull)