⚡ High-performance job queue for Bun. SQLite by default, PostgreSQL multi-broker when you scale. DLQ, cron, SQLite S3 backups, and native MCP. No Redis.
$ npx -y skills add egeominotti/bunqueue --agent claude-code
Repo: egeominotti/bunqueue
What's inside
bun add bunqueue
import { Bunqueue } from 'bunqueue/client';
const app = new Bunqueue('emails', {
embedded: true,
dataPath: './data/emails.db', // omit to run in-memory (lost on restart)
processor: async (job) => {
console.log(`Sending to ${job.data.to}`);
return { sent: true };
},
});
await app.add('send', { to: 'alice@example.com' });
That's it. Queue + Worker in one object, persisted to a single SQLite file.
No Redis, no config, no setup. msgpackr is the only runtime dependency;
cron, SQLite, S3, HTTP and WebSocket use Bun's built-ins.
The queue also runs as a standalone server. Memory is the zero-configuration default; SQLite is the zero-infrastructure persistent option:
# in-memory without --data-path; pass it to persist jobs to SQLite
bunx bunqueue start --data-path ./data/bunq.db # TCP :6789, HTTP :6790
# or, with no runtime at all (the volume persists /app/data):
docker run -d -p 6789:6789 -p 6790:6790 \
-v bunqueue-data:/app/data \
egeominotti/bunqueue:latest
For multiple active brokers, the repository includes a topology pinned to PostgreSQL 18.6:
POSTGRES_PASSWORD='replace-me' \
BUNQUEUE_POSTGRES_URL='postgres://bunqueue:replace-me@postgres:5432/bunqueue' \
docker compose -f docker-compose.postgres.yml up --build -d
It starts two brokers against one database/namespace. PostgreSQL is server-only; embedded mode keeps using memory/SQLite. Supply both Compose values when the password changes, percent-encoding reserved characters in the URL only. MySQL is not supported. CI validates PostgreSQL 15, 16, 17, and the pinned/recommended 18.6 release. See the storage guide.
All four images run the same bunqueue server with the same queue features, protocols, and persistence options. The difference is the Linux base and the tools available inside the container.
Starting with 2.9.5, completed releases publish to both Docker Hub
(egeominotti/bunqueue) and GHCR (ghcr.io/egeominotti/bunqueue), with matching
version, latest, and variant tags. Build references are kept on GHCR only.
Each image supports linux/amd64 and linux/arm64; Docker selects the matching
architecture automatically. You choose the distribution, not the CPU tag.
Pin a version or digest for reproducible deployments. Confirm a tag exists with
docker buildx imagetools inspect egeominotti/bunqueue:<tag> before using it.
Choose a Linux distribution with the same tags on either registry:
| Variant | Version tag | Moving tag | Runtime base |
|---|---|---|---|
| Alpine (default) | 2.9.5-alpine | alpine, latest | Alpine 3.22, musl |
| Debian | 2.9.5-debian | debian | Debian 13 |
| Debian slim | 2.9.5-slim | slim | Debian 13 slim |
| Distroless | 2.9.5-distroless | distroless | Debian 13, no shell or package manager |
Which variant should I use?
apk package manager. Choose it when you do not need Debian
tooling or glibc compatibility for additional software.apt.
Choose it when familiar Debian tools and a fuller base matter more than image
size. Additional troubleshooting tools may still need to be installed.apt in a reduced Debian base.
Choose it when you want Debian compatibility with fewer bundled utilities.docker exec ... sh is unavailable.The distribution does not select a faster queue engine or unlock extra features. All images run as a non-root user; having a package manager does not grant that user permission to install packages at runtime.
Try a specific variant by changing only the image tag:
docker run -d --name bunqueue --restart unless-stopped \
-p 127.0.0.1:6789:6789 -p 127.0.0.1:6790:6790 \
-v bunqueue-data:/app/data \
egeominotti/bunqueue:2.9.5-alpine
curl --fail http://127.0.0.1:6790/health
This example exposes the APIs only on your machine. Replace 2.9.5-alpine with
2.9.5-debian, 2.9.5-slim, or 2.9.5-distroless to choose another base.
Moving tags such as alpine follow newer releases; version tags identify a
release, while a digest pins the exact image even across base-image rebuilds.
Every variant supports both architectures, runs as UID/GID 1001:1001, and
stores SQLite data in /app/data. Unsuffixed tags such as 2.9.5 stay on Alpine.
Production images contain the compiled server and required system libraries;
development dependencies and a separate Bun installation stay out of the image.
The built-in health check uses /app/bunqueue healthcheck, including on distroless.
See the deployment guide for custom probes.
Prefer a standalone executable? GitHub releases include the Bun runtime, so no Bun or Node.js installation is needed. From 2.9.5, the eight downloads are:
| System | Architecture | Archive |
|---|---|---|
| Linux (glibc) | x64 | bunqueue-linux-x64.tar.gz |
| Linux (glibc) | arm64 | bunqueue-linux-arm64.tar.gz |
| Linux (musl / Alpine) | x64 | bunqueue-linux-x64-musl.tar.gz |
| Linux (musl / Alpine) | arm64 | bunqueue-linux-arm64-musl.tar.gz |
| macOS | x64 / Intel | bunqueue-darwin-x64.tar.gz |
| macOS | arm64 / Apple Silicon | bunqueue-darwin-arm64.tar.gz |
| Windows | x64 | bunqueue-windows-x64.zip |
| Windows | arm64 | bunqueue-windows-arm64.zip |
Extract the archive for your operating system and architecture, and verify it
against the release's SHA256SUMS. See the
installation guide.
Then produce and process from the language you already use:
npm install bunqueue-client # Node.js ≥ 20, Deno ≥ 2, Bun, Cloudflare Workers
import { Queue, Worker } from 'bunqueue-client';
const queue = new Queue('emails'); // localhost:6789 by default
await queue.add('welcome', { to: 'user@example.com' });
new Worker('emails', async (job) => ({ sent: true }), { concurrency: 10 });
Python, PHP, Go, Rust and Elixir clients speak the same protocol — see One Queue, Any Language.
Only the server and embedded mode are Bun-only (
bun >= 1.4.0, bun.sh); producers and workers can run anywhere.
| Library | Requires | AI-native |
|---|---|---|
| BullMQ | Redis | No |
| Agenda | MongoDB | No |
| pg-boss | PostgreSQL | No |
| bunqueue | Nothing (memory/SQLite) · PostgreSQL optional | Yes |
Queue, Worker,
QueueEvents, FlowProducer, plus QueuePro/WorkerPro aliases, fair job
groups, native processor batches, cooperative cancellation, and Observable
results; migrating takes minutesaddBulk, and
159K jobs/sec TCP PUSHB; methodology and distributionsGreat for: embedded and single-server deployments, PostgreSQL-backed broker fleets, AI agents that need a scheduler, edge/serverless spooling, and teams that don't want to operate Redis.
Not ideal for: multi-region consensus or deployments that require MySQL as the queue store. If you already run Redis and BullMQ works for you, keep it.
| Embedded | Server (TCP) | |
|---|---|---|
| How it works | Queue runs inside your process | Standalone server, clients connect via TCP |
| Setup | bun add bunqueue | docker run or bunqueue start |
| Performance | 186K jobs/sec on-disk addBulk; 729K internal in-memory batch | SQLite: 159K TCP PUSHB; 17K jobs/sec worker drain |
| Best for | Single-process apps, CLIs, serverless | Multiple workers, separate producer/consumer |
| Scaling | Same process only | Multiple clients; multiple brokers with PostgreSQL 15–18 |
Everything in your process. Without a data path the queue is in-memory: pass
dataPath (or set BUNQUEUE_DATA_PATH) to persist jobs.
import { Queue, Worker } from 'bunqueue/client';
const queue = new Queue('emails', { embedded: true, dataPath: './data/app.db' });
const worker = new Worker(
'emails',
async (job) => {
return { sent: true };
},
{ embedded: true }
);
await queue.add('welcome', { to: 'user@example.com' });
Showing a partial view of a very large repo.
FAQ
bunqueue is a Claude Code plugin with 2 hand-picked skills for automation work, indexed on Flowy. Install it with the command on its page. It includes bunqueue-dev, bunqueue. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
Is this plugin yours?
Claim it with GitHubSubmit a pluginPromote it