# BullMQ on Bun: Compatibility & SQLite Alternative

Does BullMQ work on Bun? Yes, and bunqueue removes the Redis requirement: honest benchmarks, feature differences, and when BullMQ is the better pick.

Canonical: https://bunqueue.dev/guide/comparison/

---

import { Aside } from '@astrojs/starlight/components';
import BqIcon from '@components/BqIcon.astro';

<div class="bq-wrap bq-hero">
  <span class="bq-eyebrow">guide · comparison</span>
  <h1 class="bq-hero-h1 bq-bench-h1">bunqueue vs BullMQ, one less <em>server.</em></h1>
  <p class="bq-hero-sub">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.</p>
</div>

This page helps you decide between bunqueue and BullMQ. Short version first, then the numbers with their caveats, then features.

## Quick answer

Pick **bunqueue** if you run on Bun and want embedded/single-broker SQLite or a
PostgreSQL 15–18 multi-broker server without Redis; 18.6 is recommended. You get the same Queue and
Worker API across these server backends.

Pick **BullMQ** if Redis/Redis Cluster is already your operational standard, you
need Redis-specific behavior, or you cannot run a Bun broker. Details in
[When to Use BullMQ Instead](#when-to-use-bullmq-instead).

## The numbers

<div class="bq-cards">
  <div class="bq-card">
    <BqIcon name="speed" />
    <h3>1.3x Faster Push</h3>
    <p><b>54,140 vs 43,261 ops/sec</b></p>
    <p>Single job push</p>
  </div>
  <div class="bq-card">
    <BqIcon name="spark" />
    <h3>3.2x Faster Bulk</h3>
    <p><b>139,200 vs 44,000 ops/sec</b></p>
    <p>Bulk push, 100 jobs per batch</p>
  </div>
  <div class="bq-card">
    <BqIcon name="check" />
    <h3>Lower Bulk Latency</h3>
    <p><b>3.26 vs 4.53 ms p99</b></p>
    <p>Bulk push tail latency</p>
  </div>
  <div class="bq-card">
    <BqIcon name="file" />
    <h3>Zero Infrastructure</h3>
    <p><b>No Redis required</b></p>
    <p>Embedded SQLite. One direct runtime dependency.</p>
  </div>
</div>

| 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** |

:::note[Read this before quoting numbers]
Benchmark figures depend on hardware and library versions, and they change across bunqueue versions. Two things to know:

1. A more recent run (2026-07-08, Apple M1 Max, Bun 1.3.14, BullMQ 5.79.3, Redis 8.8.0) measured **bulk push at 85,700 vs 24,800 ops/sec (3.5x)** with **single push at parity**. It is summarized on the [home page](/) with full methodology.
2. This page does not quote a Process (end-to-end job consumption) figure. Older published Process numbers predate a worker-leasing correctness fix in 2.8.18 that bounds how many jobs one TCP worker can lease. A single worker at `concurrency: 50` now measures in the thousands of ops/sec, and end-to-end throughput scales with worker count, not queue depth. See the [benchmarks page](/guide/benchmarks/) for current numbers.

Reproduce either run with `bun run bench/comparison/run.ts`.

All bunqueue figures on this page measure the memory/SQLite engine. PostgreSQL
18.6 functional tests are not benchmarks and these numbers must not be applied
to the multi-broker backend.
:::

<Aside type="note">
  This is a fair comparison: both systems go over the network (bunqueue TCP vs Redis TCP), same
  payload size (100 bytes), same batch sizes, same push strategy. Embedded mode (queue inside your
  process, no network) benchmarks significantly higher; see [benchmarks](/guide/benchmarks/).
</Aside>

<div class="bq-chart-grid">
  <div class="bq-chart">
    <p class="bq-chart-title">Push <span>ops/sec, higher is better</span></p>
    <div class="bq-hrow">
      <span class="bq-hname">bunqueue</span>
      <div class="bq-htrack">
        <div class="bq-hfill" style="width:100%"></div>
      </div>
      <span class="bq-hval">54,140</span>
    </div>
    <div class="bq-hrow">
      <span class="bq-hname">BullMQ</span>
      <div class="bq-htrack">
        <div class="bq-hfill bq-hfill-them" style="width:80%"></div>
      </div>
      <span class="bq-hval">43,261</span>
    </div>
    <p class="bq-chart-note"><b>1.3x faster</b></p>
  </div>
  <div class="bq-chart">
    <p class="bq-chart-title">Bulk push <span>ops/sec, higher is better</span></p>
    <div class="bq-hrow">
      <span class="bq-hname">bunqueue</span>
      <div class="bq-htrack">
        <div class="bq-hfill" style="width:100%"></div>
      </div>
      <span class="bq-hval">139,200</span>
    </div>
    <div class="bq-hrow">
      <span class="bq-hname">BullMQ</span>
      <div class="bq-htrack">
        <div class="bq-hfill bq-hfill-them" style="width:32%"></div>
      </div>
      <span class="bq-hval">44,000</span>
    </div>
    <p class="bq-chart-note"><b>3.2x faster</b></p>
  </div>
  <div class="bq-chart">
    <p class="bq-chart-title">Bulk push p99 <span>ms, lower is better</span></p>
    <div class="bq-hrow">
      <span class="bq-hname">bunqueue</span>
      <div class="bq-htrack">
        <div class="bq-hfill" style="width:72%"></div>
      </div>
      <span class="bq-hval">3.26 ms</span>
    </div>
    <div class="bq-hrow">
      <span class="bq-hname">BullMQ</span>
      <div class="bq-htrack">
        <div class="bq-hfill bq-hfill-them" style="width:100%"></div>
      </div>
      <span class="bq-hval">4.53 ms</span>
    </div>
    <p class="bq-chart-note"><b>1.4x lower</b></p>
  </div>
</div>

**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

- **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

| 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                                                | ✅                                                  | ✅                                   |
| Pro-style job groups                                               | ✅ Priority/FIFO, max size, pause, limits           | ✅ BullMQ Pro                        |
| Native processor batches                                          | ✅ Bun client, selective member failure             | ✅ BullMQ Pro                        |
| AbortSignal / Observable processors                                | ✅ Bun client                                       | ✅ BullMQ Pro                        |
| Pro telemetry / NestJS integration                                 | ❌ Use native metrics; framework-neutral            | ✅ BullMQ Pro                        |
| Persistence                                                       | Memory/SQLite by default; PostgreSQL 15–18 optional | Redis server                         |
| Horizontal broker scaling                                         | ✅ PostgreSQL mode                                  | ✅ Redis Cluster                     |
| External infrastructure                                           | ✅ None with SQLite; PostgreSQL optional            | ❌ Redis required                    |
| Built-in S3 backup                                                | ✅ SQLite mode                                      | ❌ Manual                            |
| MCP server for AI agents                                          | ✅ Built-in                                         | ❌                                   |
| Client languages                                                  | TypeScript, Python, PHP, Go, Rust, Elixir           | Node.js, Python, and community ports |

## When to Use BullMQ Instead

bunqueue's SQLite mode is single-broker; its PostgreSQL mode supports multiple
brokers. BullMQ is still the better pick when:

- **Redis Cluster is a hard requirement** or already provides your queue HA model.
- **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.
- **You cannot run on Bun.** bunqueue's server and embedded mode require the Bun runtime.

<Aside>
  For single-process apps, a service plus its workers, edge deployments, or a PostgreSQL-backed
  broker fleet, bunqueue keeps the same client API.
</Aside>

## Run it yourself

```bash
git clone https://github.com/egeominotti/bunqueue.git
cd bunqueue && bun install
redis-server --daemonize yes   # BullMQ side
bun run start &                # bunqueue server
bun run bench/comparison/run.ts
```

Source: [`bench/comparison/run.ts`](https://github.com/egeominotti/bunqueue/blob/main/bench/comparison/run.ts).

<Aside type="tip" title="Related">
  - [Migration from BullMQ](/guide/migration/), the step-by-step switch -
  [Benchmarks](/guide/benchmarks/), full throughput and latency numbers - [Production
  Operations](/guide/production/), what running bunqueue actually costs
</Aside>