Stem vs BullMQ
This page is the canonical Stem comparison matrix for BullMQ-style features. It focuses on capability parity, not API-level compatibility.
As of: February 24, 2026
Status semantics
| Status | Meaning |
|---|---|
✓ | Functionally equivalent built-in capability exists in Stem. |
~ | Partial or non-isomorphic capability exists, but semantics differ from BullMQ/BullMQ-Pro. |
✗ | No built-in capability in Stem today. |
Feature matrix
| BullMQ row | Stem | Rationale (with evidence) |
|---|---|---|
| Backend | ✓ | Stem supports multiple backends/adapters (Redis, Postgres, SQLite, in-memory). See Broker Overview and Developer Environment. |
| Observables | ✓ | Stem has built-in metrics, tracing, and lifecycle signals. See Observability and Signals. |
| Group Rate Limit | ✓ | Stem supports group-scoped rate limiting via TaskOptions.groupRateLimit, groupRateKey, and groupRateKeyHeader. See Rate Limiting. |
| Group Support | ✓ | Stem provides Canvas.group and Canvas.chord primitives. See Canvas Patterns. |
| Batches Support | ✓ | Stem exposes first-class batch APIs (submitBatch, inspectBatch) with durable batch lifecycle status. See Canvas Patterns. |
| Parent/Child Dependencies | ✓ | Stem supports dependency composition through chains, groups/chords, and workflow steps. See Canvas Patterns and Workflows. |
| Deduplication (Debouncing) | ~ | TaskOptions.unique prevents duplicate enqueue claims, but semantics are lock/TTL-based rather than BullMQ-native dedupe APIs. See Uniqueness. |
| Deduplication (Throttling) | ~ | uniqueFor and lock TTL windows approximate throttling behavior, but are not a direct BullMQ equivalent. See Uniqueness. |
| Priorities | ✓ | Stem supports task priority and queue priority ranges. See Tasks and Routing. |
| Concurrency | ✓ | Workers support configurable concurrency and isolate pools. See Workers and Worker Control. |
| Delayed jobs | ✓ | Delayed execution is supported via enqueue options and broker scheduling. See Quick Start and Broker Overview. |
| Global events | ✓ | Stem exposes global lifecycle events through StemSignals, plus queue-scoped custom events through QueueEvents. See Signals and Queue Events. |
| Rate Limiter | ✓ | Stem supports per-task rate limits with pluggable limiter backends. See Rate Limiting. |
| Pause/Resume | ✓ | Stem provides queue pause/resume commands (stem worker pause, stem worker resume) and persistent pause state when a revoke store is configured. See Worker Control. |
| Sandboxed worker | ~ | Stem supports isolate-based execution boundaries, but this is not equivalent to BullMQ's Node child-process sandbox model. See Worker Control. |
| Repeatable jobs | ✓ | Stem Beat supports interval, cron, solar, and clocked schedules. See Scheduler and Beat Scheduler Guide. |
| Atomic ops | ~ | Stem includes atomic behavior in specific stores/flows, but end-to-end transactional guarantees (for all enqueue/ack/result paths) are not universally built-in. See Tasks idempotency guidance and Best Practices. |
| Persistence | ✓ | Stem persists task/workflow/schedule state through pluggable backends/stores. See Persistence & Stores. |
| UI | ~ | Stem includes an experimental dashboard, not a fully mature operator UI parity target yet. See Dashboard. |
| Optimized for | ~ | Stem is optimized for jobs/messages plus durable workflow orchestration, not only queue semantics. See Core Concepts and Workflows. |
Update policy
When this matrix changes:
- Update the As of date.
- Keep row names aligned with BullMQ terminology.
- Update rationale links so every status remains auditable.
BullMQ events parity notes
Stem supports the two common BullMQ event-listening styles:
| BullMQ concept | Stem equivalent |
|---|---|
QueueEvents listeners | QueueEvents + QueueEventsProducer (queue-scoped custom events) |
| Custom queue events | producer.emit(queue, eventName, payload, headers, meta) |
| Worker-specific event listeners | StemSignals convenience APIs with workerId filters (onWorkerReady, onWorkerInit, onTaskFailure, onControlCommandCompleted, etc.) |