Why
BullMQ gives you persistent, retriable background jobs backed by Redis — the same Redis instance already used for caching. It ships with a dev UI (Bull Board), supports DLQs, and slots into the pluggable tooling system so you can swap it for another provider by changing one config value.Setup
- In
apps/backend/package.json, ensure"tooling-queue-bullmq": "workspace:*"is listed underdependenciesand remove any other queue adapter package. - Run
make deps-install. - In
development.ts,production.ts, andtest.ts, settools.queue: - In
compose.yml, add thememoryRedis service andbullmq-adminif not already present, and pointbackend,consumer, andmigratoratdepends_on: memory: - In
.env.development, setREDIS_URL=redis://memory:6379. - Run
make test module=tooling-queue-bullmqandmake test module=backend.
Local observability
Bull Board runs at http://localhost:3998 — it shows queue depth, job state, retries, and DLQ contents in real time. It reads directly from Redis, so it only reflects traffic when BullMQ is the active provider.Adding a new queue
See Queue overview for the full client-agnostic steps (registry, config, consumer handler).Gotchas
- Bull Board only shows traffic for the active provider. If you switch providers, the UI goes dark — that’s expected.
- Never mix queue providers between the API and consumer services in the same deployment.
- The
memoryRedis service is shared betweentools.cacheandtools.queue. PointingREDIS_URLat a different instance for one tool will break the other unless you split the config intentionally. - Never paste a production
REDIS_URLinto.env.development— rotate credentials immediately if that happens.
What’s next?
- Queue overview — consumers, deferred send, scaling rules.
- Scheduler overview — recurring work (may use SQS for execution).
- SQS — full guide to adopting SQS as an alternative provider.
- Configuration — switching pluggable tool implementations.
- Tooling system — how loaders and workspace packages fit together.
