Bunqueue vs BullMQ: Performance Comparison & Feature Differences
bunqueue vs BullMQ, one less server.
Real benchmark results comparing the bunqueue TCP server against BullMQ with Redis on identical workloads, a full feature comparison, and the cases where BullMQ is still the better pick.
Summary
Section titled “Summary”1.3x Faster Push
54,140 vs 43,261 ops/sec
Single job push operations
3.2x Faster Bulk
139,200 vs 44,000 ops/sec
Bulk push (100 jobs per batch)
1.7x Faster Processing
33,052 vs 19,225 ops/sec
Job processing throughput
Zero Infrastructure
No Redis Required
Embedded SQLite vs Redis server. 7 packages, 5.5 MB installed.
Throughput Comparison
Section titled “Throughput Comparison”Push ops/sec, higher is better
1.3x faster
Bulk push ops/sec, higher is better
3.2x faster
Process ops/sec, higher is better
1.7x faster
| Operation | bunqueue | BullMQ | Speedup |
|---|---|---|---|
| Push | 54,140 ops/sec | 43,261 ops/sec | 1.3x faster |
| Bulk Push | 139,200 ops/sec | 44,000 ops/sec | 3.2x faster |
| Process | 33,052 ops/sec | 19,225 ops/sec | 1.7x faster |
Latency Comparison
Section titled “Latency Comparison”Bulk push p99 latency ms, lower is better
1.4x lower
| Operation | bunqueue p99 | BullMQ p99 | Improvement |
|---|---|---|---|
| Bulk Push | 3.26ms | 4.53ms | 1.4x lower |
Speedup by Operation
Section titled “Speedup by Operation”Speedup by operation bunqueue ÷ BullMQ, higher is better
How the Benchmark Works
Section titled “How the Benchmark Works”The benchmark performs three tests for both bunqueue and BullMQ:
1. Push Test
Section titled “1. Push Test”Pushes 10,000 jobs using 32 parallel connections to measure raw push throughput.
// 32 concurrent clients pushing jobsawait benchmarkParallel('Push', async () => { await queue.add('job', PAYLOAD);}, 10000, 32);2. Bulk Push Test
Section titled “2. Bulk Push Test”Pushes 100 jobs per batch, 1,000 times (100,000 total jobs) to measure bulk insertion performance.
// Batch of 100 jobs per operationconst jobs = Array.from({ length: 100 }, (_, i) => ({ name: 'bulk-job', data: { ...PAYLOAD, i },}));await queue.addBulk(jobs);3. Process Test
Section titled “3. Process Test”Measures end-to-end throughput: pushing 10,000 jobs and processing them with a single worker at concurrency: 50 (50 jobs in flight).
// Push jobs in parallel batchesfor (let i = 0; i < 10000; i += 1000) { await Promise.all(batch.map(() => queue.add('job', PAYLOAD)));}
// Wait for all to be processedwhile (processed < 10000) { await new Promise(r => setTimeout(r, 10));}Why is bunqueue Faster?
Section titled “Why is bunqueue Faster?”TCP Pipelining
bunqueue’s TCP protocol supports pipelining - multiple commands in flight per connection, with reqId-based response matching.
Optimized Data Structures
Skip lists, MinHeap, and LRU cache provide O(log n) or O(1) operations for common tasks.
Batch Transactions
SQLite transactions batch multiple operations into single disk writes with WAL mode.
Auto-Scaled Sharding
Lock contention is minimized by distributing work across N independent shards (auto-detected from CPU cores, max 64).
Feature Comparison
Section titled “Feature Comparison”| Feature | bunqueue | BullMQ |
|---|---|---|
| Queue Types | ✅ Standard, Priority, LIFO | ✅ Standard, Priority, LIFO |
| Delayed Jobs | ✅ Yes | ✅ Yes |
| Retries & Backoff | ✅ Exponential | ✅ Exponential |
| Dead Letter Queue | ✅ Built-in (auto-retry, expiration) | ⚠️ Failed set, no dedicated DLQ |
| Rate Limiting | ✅ Per-queue | ✅ Per-queue |
| Cron Jobs | ✅ Built-in | ✅ Via scheduler |
| Job Dependencies | ✅ Parent-child flows | ✅ Parent-child flows |
| Persistence | ✅ SQLite (embedded) | ✅ Redis |
| Horizontal Scaling | ⚠️ Single process | ✅ Multi-process |
| External Dependencies | ✅ None (2 runtime deps) | ❌ Redis required |
| Install Footprint | ✅ 7 packages, 5.5 MB | ❌ ~3 MB lib + Redis server |
| S3 Backup | ✅ Built-in | ❌ Manual |
| TCP Pipelining | ✅ Built-in | ✅ Via Redis |
| MCP Server (AI Agents) | ✅ 73 tools built-in | ❌ Not available |
Run the Benchmark Yourself
Section titled “Run the Benchmark Yourself”The benchmark source code is available at bench/comparison/run.ts.
# Clone the repositorygit clone https://github.com/egeominotti/bunqueue.gitcd bunqueuebun install
# Start Redis (required for BullMQ)redis-server --daemonize yes
# Start bunqueue serverbun run start &
# Run the benchmarkbun run bench/comparison/run.tsBenchmark Output
Section titled “Benchmark Output”Run with Redis connected and the bunqueue server connected on port 6789.
Benchmark Environment
Section titled “Benchmark Environment”Hardware:
- Mac Studio, Apple M1 Max
- 32GB RAM
- SSD storage
Software:
- macOS Tahoe
- Bun 1.3.8
- Redis 7.x (localhost)
Configuration:
- 10,000 iterations per test
- Bulk size: 100 jobs
- Concurrency: 50 workers
- Payload: 100 bytes per job
- TCP pipelining enabled
- Connection pool: 32 connections
When to Use BullMQ Instead
Section titled “When to Use BullMQ Instead”While bunqueue is faster for most use cases, BullMQ may be better when:
- Horizontal scaling is required across multiple processes/servers
- Redis is already part of your infrastructure
- Redis-specific features like pub/sub or Lua scripts are needed
- Workers in languages beyond bunqueue’s official SDKs (TypeScript and Python) need to share the same queue