bunqueue vs BullMQ, one less server.
Benchmark results comparing the bunqueue TCP server against BullMQ with Redis on identical workloads, a feature comparison, and the cases where BullMQ is still the better pick.
This page helps you decide between bunqueue and BullMQ. Short version first, then the numbers with their caveats, then features.
Quick answer
Section titled “Quick answer”Pick bunqueue if you run on Bun and one queue server (or one process, in embedded mode) is enough. You get the same Queue and Worker API as BullMQ with no Redis to install, monitor, or pay for. Jobs persist in a SQLite file.
Pick BullMQ if you need to scale the queue itself across multiple servers, already operate Redis, or need workers in languages beyond bunqueue’s official SDKs (TypeScript and Python). Details in When to Use BullMQ Instead.
The numbers
Section titled “The numbers”1.3x Faster Push
54,140 vs 43,261 ops/sec
Single job push
3.2x Faster Bulk
139,200 vs 44,000 ops/sec
Bulk push, 100 jobs per batch
Lower Bulk Latency
3.26 vs 4.53 ms p99
Bulk push tail latency
Zero Infrastructure
No Redis required
Embedded SQLite. 7 packages, 5.5 MB installed.
| Operation | bunqueue | BullMQ | Speedup |
|---|---|---|---|
| Push (single job) | 54,140 ops/sec | 43,261 ops/sec | 1.3x |
| Bulk push (100 per batch) | 139,200 ops/sec | 44,000 ops/sec | 3.2x |
| Bulk push p99 latency | 3.26 ms | 4.53 ms | 1.4x lower |
Push ops/sec, higher is better
1.3x faster
Bulk push ops/sec, higher is better
3.2x faster
Bulk push p99 ms, lower is better
1.4x lower
Environment for the table above: Mac Studio (Apple M1 Max, 32 GB, SSD), macOS Tahoe, Bun 1.3.8, Redis 7.x on localhost. 10,000 iterations per test, bulk size 100, payload 100 bytes, 32-connection pool with pipelining.
Why bunqueue is faster on these workloads
Section titled “Why bunqueue is faster on these workloads”- TCP pipelining: many commands in flight per connection, responses matched by request id.
- Batched writes: SQLite in WAL mode (write-ahead logging, a journal that lets reads and writes overlap) groups many jobs into one disk transaction.
- Sharding: work is spread across independent shards sized to your CPU cores, which keeps lock contention low.
- In-memory hot path: the ready queue lives in memory (skip lists, heaps, LRU caches), SQLite is the durability layer, not the dispatcher.
Feature comparison
Section titled “Feature comparison”| Feature | bunqueue | BullMQ |
|---|---|---|
| Queue types (standard, priority, LIFO) | ✅ | ✅ |
| Delayed jobs, retries with backoff | ✅ | ✅ |
| Dead letter queue (holding area for jobs that failed all retries) | ✅ Built-in, with auto-retry and expiration | ⚠️ Failed set, no dedicated DLQ |
| Rate limiting | ✅ Per-worker and per-queue | ✅ Per-worker |
| Cron / repeatable jobs | ✅ Built-in | ✅ Via Job Scheduler |
| Parent-child flows | ✅ | ✅ |
| Persistence | SQLite file, embedded | Redis server |
| Horizontal scaling of the queue itself | ❌ Single instance | ✅ Redis Cluster |
| External dependencies | ✅ None (2 runtime deps) | ❌ Redis required |
| S3 backup | ✅ Built-in | ❌ Manual |
| MCP server for AI agents | ✅ Built-in | ❌ |
| Client languages | TypeScript, Python | Node.js, Python, and community ports |
When to Use BullMQ Instead
Section titled “When to Use BullMQ Instead”bunqueue is single-instance: one server process owns the SQLite file, and workers connect to it. BullMQ is the better pick when:
- The queue itself must scale horizontally across multiple servers (Redis Cluster).
- Redis is already in your stack and operating it costs you nothing extra.
- You need Redis-specific features such as pub/sub fan-out or custom Lua scripts.
- Your workers are written in languages outside bunqueue’s official SDKs (TypeScript and Python).
- You cannot run on Bun. bunqueue’s server and embedded mode require the Bun runtime.
Run it yourself
Section titled “Run it yourself”git clone https://github.com/egeominotti/bunqueue.gitcd bunqueue && bun installredis-server --daemonize yes # BullMQ sidebun run start & # bunqueue serverbun run bench/comparison/run.tsSource: bench/comparison/run.ts.