Enables AI agents and automation to manage high-performance job queues using SQLite or PostgreSQL without requiring Redis.
Also known as egeominotti/bunqueue
- Stars
- 592
- Tools
- —
- Downloads, 30 days
- —
- Latest version
- —
- Last commit
- Nov 13, 2026
- License
- MIT
What is bunqueue MCP?
bunqueue is an MCP server. Enables AI agents and automation to manage high-performance job queues using SQLite or PostgreSQL without requiring Redis.
Summary generated from the project's README
About bunqueue MCP server
bunqueue provides a high-performance job queue system designed specifically for AI agents and automation tasks. It eliminates the need for Redis by utilizing memory or a single-file SQLite database for local setups. For larger scale requirements, it supports PostgreSQL 15 through 18 as a multi-broker backend. This makes it an ideal choice for developers who want to manage background tasks without managing complex infrastructure.
Users can run the system in an embedded mode directly within a Bun application or deploy it as a standalone server using Docker or single-binary executables. The server supports various Linux distributions including Alpine, Debian, and Distroless. Once the server is running, clients can connect from many different environments including Node.js, Python, PHP, Go, Rust, and Elixir. The system includes built-in features like dead letter queues, cron scheduling, and SQLite S3 backups to ensure reliable job processing.
What you can do with it
- 1Manage background tasks without RedisA developer can set up a job queue using only memory or a local SQLite file to avoid the complexity of extra servers.
- 2Scale automation with PostgreSQLYou can transition from a local setup to a multi-broker architecture by connecting to a PostgreSQL database.
- 3Integrate with diverse programming languagesAn AI agent written in Python or Go can communicate with the same queue as a Bun-based worker.
- 4Handle failed jobs with DLQDevelopers can use dead letter queues to manage retries and inspect jobs that failed to process.
Written from the project's README. Every use case is checked against a quote from it.
How to install bunqueue MCP
Formats verified 10 Nov 2026Install bunqueue MCP in Claude Code
$ claude mcp add bunqueue -- npx -y bunqueueInstall bunqueue MCP in Cursor
~/.cursor/mcp.json
{
"mcpServers": {
"bunqueue": {
"command": "npx",
"args": [
"-y",
"bunqueue"
]
}
}
}Install bunqueue MCP in VS Code
.vscode/mcp.json
{
"servers": {
"bunqueue": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"bunqueue"
]
}
}
}Install bunqueue MCP in Claude Desktop
claude_desktop_config.json
{
"mcpServers": {
"bunqueue": {
"command": "npx",
"args": [
"-y",
"bunqueue"
]
}
}
}Install bunqueue MCP in Codex
~/.codex/config.toml
[mcp_servers.bunqueue] command = "npx" args = ["-y", "bunqueue"]
Install bunqueue MCP in Gemini CLI
~/.gemini/settings.json
{
"mcpServers": {
"bunqueue": {
"command": "npx",
"args": [
"-y",
"bunqueue"
]
}
}
}Configuration
BUNQUEUE_MCP_PROFILEBUNQUEUE_POSTGRES_URLPOSTGRES_PASSWORD
| Name | Description | |
|---|---|---|
| BUNQUEUE_MCP_PROFILE | — | |
| BUNQUEUE_POSTGRES_URL | — | |
| POSTGRES_PASSWORD | — |
Automated checks
Ran Nov 12, 2026Full report →Passed our automated checks. That is not a security audit: read the code and give the server the narrowest access it needs. How checks work
- Source repository linked and reachablePass
- Open source license (OSI)Pass
- Commit or release in the last yearPass
- Package name not close to a popular packagePass
- Remote endpoint uses HTTPSNot checked
- Destructive tools are labelledNot checked
- No hidden instructions to the modelPass
- No critical advisory in the package or its dependenciesNot checked
README
View on GitHubQuickstart
Your first job in about a minute. On Bun the queue runs inside your app, with no server to start:
bun add bunqueue
// jobs.ts
import { Queue, Worker } from 'bunqueue/client';
const queue = new Queue<{ to: string }>('emails', { embedded: true });
const worker = new Worker<{ to: string }>(
'emails',
async (job) => {
console.log('Processing:', job.data.to);
return { sent: true };
},
{ embedded: true }
);
worker.on('error', (error) => console.error(error));
await queue.add('welcome', { to: 'hello@example.com' });
bun jobs.ts
# Processing: hello@example.com
That's it: no Redis, no config, no setup. The worker keeps waiting for more jobs
until you stop it with Ctrl+C. The example keeps jobs in memory; pass
dataPath: './jobs.db' to the queue and the worker to persist them in one
SQLite file. msgpackr is the only runtime dependency; cron, SQLite, S3, HTTP and
WebSocket use Bun's built-ins.
Not on Bun? Run the server, connect from anywhere
Start the server with Docker (no Bun needed) or, if Bun is installed, with
bunx bunqueue start --host 127.0.0.1 --data-path ./bunqueue.db:
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:alpine
curl --fail http://127.0.0.1:6790/health
Then, in another terminal, add a job and process it from Node.js:
npm install bunqueue-client
// jobs.mjs
import { Queue, Worker } from 'bunqueue-client';
const options = {
embedded: false,
connection: { host: '127.0.0.1', port: 6789 },
};
const queue = new Queue('emails', options);
const worker = new Worker(
'emails',
async (job) => {
console.log('Processing:', job.data.to);
return { sent: true };
},
options
);
worker.on('error', (error) => console.error(error));
await queue.add('welcome', { to: 'hello@example.com' });
node jobs.mjs
# Processing: hello@example.com
Deno, Python, PHP, Go, Rust and Elixir take the same three steps: see the Quick Start for each language.
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.
Docker images
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.21-alpine |
alpine, latest |
Alpine 3.22, musl |
| Debian | 2.9.21-debian |
debian |
Debian 13 |
| Debian slim | 2.9.21-slim |
slim |
Debian 13 slim |
| Distroless | 2.9.21-distroless |
distroless |
Debian 13, no shell or package manager |
Which variant should I use?
- Alpine is the default for a compact deployment. It uses musl and includes
a shell and the
apkpackage manager. Choose it when you do not need Debian tooling or glibc compatibility for additional software. - Debian uses glibc and the standard Debian base, with a shell and
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. - Debian slim keeps glibc, a shell, and
aptin a reduced Debian base. Choose it when you want Debian compatibility with fewer bundled utilities. - Distroless contains the compiled server and its required runtime libraries,
without a shell or package manager. Choose it when you operate through logs,
health checks, and external debugging tools;
docker exec ... shis 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.21-alpine
curl --fail http://127.0.0.1:6790/health
This example exposes the APIs only on your machine. Replace 2.9.21-alpine with
2.9.21-debian, 2.9.21-slim, or 2.9.21-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.21 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.
Standalone executables and network clients
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.
Learn with bunqueue Academy
A free video course on YouTube, from your first queue to production. Each episode follows a guide on bunqueue.dev, with chapters and English subtitles.
| # | Episode | Length | Guide |
|---|---|---|---|
| 00 | Introducing bunqueue | 1:01 | Introduction |
| 01 | Quickstart: build your first job queue | 19:14 | Quick Start |
| 02 | Queue: add, deduplicate and control jobs | 25:37 | Queue |
| 03 | Workers: concurrency, leases and retries | 24:46 | Worker |
| 04 | Cron and scheduling that survive restarts | 19:44 | Cron |
| 05 | Dead letter queue: retries, backoff and failed jobs | 21:12 | Dead Letter Queue |
| 06 | FlowProducer: parent and child job dependencies | 18:56 | Flow Producer |
Coming next: 07 Workflow Engine · 08 SDKs, CLI & MCP · 09 Production · 10 Framework Integrations.
Full playlist → · All episodes on bunqueue.dev →
Why bunqueue?
| Library | Requires | AI-native |
|---|---|---|
| BullMQ | Redis | No |
| Agenda | MongoDB | No |
| pg-boss | PostgreSQL | No |
| bunqueue | Nothing (memory/SQLite) · PostgreSQL optional | Yes |
- Zero external infrastructure by default — memory by default; one SQLite file when local persistence is configured
- PostgreSQL 15–18 multi-broker mode — PostgreSQL 18.6 is recommended; database-authoritative claims, fenced leases, shared limits, cron, workers, job-state/lifecycle metrics, and failover state (tested three-broker Docker example)
- BullMQ and BullMQ Pro-compatible API —
Queue,Worker,QueueEvents,FlowProducer, plusQueuePro/WorkerProaliases, fair job groups, native processor batches, cooperative cancellation, and Observable results; migrating takes minutes - MCP server included — 79 primary tools; AI agents get full queue control out of the box
- Everything server-side — retries with backoff, priorities, cron, rate limits, dead letter queue
- Measured, operation-specific performance — 729K jobs/sec internal
in-memory batch push, 186K jobs/sec public on-disk Embedded
addBulk, and 159K jobs/sec TCPPUSHB; methodology and distributions
Great 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.
Two Modes
| 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 |
Embedded
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' });
Server (TCP)
docker run -d -p 6789:6789 -p 6790:6790 \
-v bunqueue-data:/app/data \
egeominotti/bunqueue:latest
import { Queue, Worker } from 'bunqueue/client';
const queue = new Queue('tasks', { connection: { host: 'localhost', port: 6789 } });
const worker = new Worker(
'tasks',
async (job) => {
return { done: true };
},
{ connection: { host: 'localhost', port: 6789 } }
);
await queue.add('process', { data: 'hello' });
Running the server → · Deployment guide →
BullMQ Pro-compatible groups and batches
The Bun client exposes Pro-style aliases backed by the same native queue and worker implementations. No separate runtime or license is required:
import { QueuePro, WorkerPro } from 'bunqueue/client';
const queue = new QueuePro('webhooks', { embedded: true, dataPath: './data/app.db' });
await queue.add('deliver', payload, {
group: { id: 'tenant-a', priority: 1, maxSize: 10_000 },
});
const worker = new WorkerPro(
'webhooks',
async (job, { signal } = { signal: new AbortController().signal }) => {
const batch = job.getBatch?.() ?? [job];
return await deliver(batch, signal);
},
{
embedded: true,
batch: { size: 100, minSize: 10, timeout: 250, groupAffinity: true },
group: { concurrency: 2, limit: { max: 20, duration: 1000 } },
}
);
Groups support atomic maxSize admission, priority within a group, pause and
resume, manual rate limits, per-group concurrency/rate defaults, pending-job
queries, and fair round-robin claims. Native batches support minimum size,
timeout, group affinity, and selective job.setAsFailed(error). Processor
timeouts and explicit cancellation abort the second-argument AbortSignal;
Promise handlers remain cooperative, while structural Observable handlers are
unsubscribed. These contracts are identical with SQLite and PostgreSQL 15–18.
BullMQ Pro telemetry and NestJS integration are intentionally not included.
Job Groups guide → · Worker options →
One Queue, Any Language (SDKs)
The server does all the heavy lifting. Official client SDKs share the protocol-conformant core Queue, Worker, and Flow surface, so producers and workers can live anywhere in your stack — add a job from TypeScript, process it from Python. Language-specific capabilities are tracked in the SDK guide.
| Where your code runs | Install |
|---|---|
| Node.js ≥ 20, Deno ≥ 2, Bun, Cloudflare Workers | npm install bunqueue-client |
| Python ≥ 3.9 | pip install bunqueue-client |
| PHP ≥ 8.1 | composer require bunqueue/client |
| Go ≥ 1.26.5 | go get github.com/egeominotti/bunqueue/sdk/go |
| Rust ≥ 1.85 | cargo add bunqueue-client |
| Elixir ≥ 1.15 | Hex coming soon — today: use sdk/elixir as a path dependency |
// Node.js / Deno / Cloudflare Workers
import { Queue, Worker } from 'bunqueue-client';
const queue = new Queue('emails', { connection: { host: 'localhost', port: 6789 } });
await queue.add('welcome', { to: 'user@example.com' });
new Worker('emails', async (job) => ({ sent: true }), { concurrency: 10 });
# Python
from bunqueue import Queue, Worker
queue = Queue("emails", host="localhost", port=6789)
queue.add("welcome", {"to": "user@example.com"})
Worker("emails", lambda job: {"sent": True}, concurrency=10).run()
Every SDK is certified against the same public wire protocol and conformance suite.
Atomic flows, in every SDK
Every official FlowProducer resolves all job IDs and reciprocal dependency
edges locally, then sends one PUSHF command. The broker validates the complete
graph and commits it atomically, so a worker cannot observe a leaf from a
partially-created flow.
import { FlowProducer } from 'bunqueue-client';
const flows = new FlowProducer({ connection: { host: 'localhost', port: 6789 } });
const root = await flows.add({
name: 'publish-release',
queueName: 'release',
data: { version: 'candidate-42' },
children: [
{ name: 'unit-tests', queueName: 'checks', data: { suite: 'unit' } },
{ name: 'sdk-tests', queueName: 'checks', data: { suite: 'sdk' } },
],
});
console.log(
root.job.id,
root.children?.map(({ job }) => job.id)
);
await flows.close();
The repository records the contracts and the test strategy beside each implementation:
| SDK | Runtime invariants | Generated tests | Mutation engine |
|---|---|---|---|
| TypeScript | contract | fast-check | none¹ |
| Python | contract | Hypothesis | mutmut |
| PHP | contract | Eris | Infection |
| Go | contract | Rapid | Gremlins |
| Rust | contract | proptest | cargo-mutants |
| Elixir | contract | StreamData | Muex |
¹ The TypeScript SDK has no mutation engine. StrykerJS was removed because its dependency graph produced every advisory the weekly audit had to answer for, none of it reachable from the published client; the planners keep their fast-check coverage.
Property campaigns run in the ordinary SDK gate with deterministic replay
seeds. Mutation campaigns run separately against the pure planners and
snapshot validators. Contributors can reproduce the complete isolated SDK
gate with bun run test:sandbox:sdk; language-specific commands live in each
SDK README and AGENTS.md.
SDK guide (all six languages) →
Simple Mode
Bunqueue bundles Queue + Worker + routes + middleware + cron in one object:
import { Bunqueue } from 'bunqueue/client';
const app = new Bunqueue('notifications', {
embedded: true,
routes: {
'send-email': async (job) => ({ sent: true }),
'send-sms': async (job) => ({ sent: true }),
},
concurrency: 10,
retry: { maxAttempts: 5, strategy: 'jitter' },
circuitBreaker: { threshold: 5, resetTimeout: 30000 },
});
// Onion middleware around every job
app.use(async (job, next) => {
const start = Date.now();
const result = await next();
console.log(`${job.name}: ${Date.now() - start}ms`);
return result;
});
await app.cron('daily-report', '0 9 * * *', { type: 'summary' });
await app.add('send-email', { to: 'alice@example.com' });
app.on('completed', (job, result) => console.log(result));
await app.close();
Also included: batch processing, event triggers (job A completes → create job
B), job TTL, priority aging, deduplication, per-group rate limiting, DLQ with
auto-retry, graceful cancellation via AbortController.
bunqueue MCP questions
How do I add bunqueue MCP to Claude Code?
Run claude mcp add bunqueue -- npx -y bunqueue in your terminal. Add --scope user to make it available in every project.
How do I add bunqueue MCP to Cursor?
Open ~/.cursor/mcp.json and add the server under mcpServers, using the Cursor config shown in the install section above.
Does bunqueue require Redis?
No, bunqueue does not require Redis; it uses memory or SQLite by default and can scale to PostgreSQL.
Can I run bunqueue without Bun installed?
Yes, you can run the server using Docker or use standalone executables from GitHub releases that include the Bun runtime.
What languages can connect to the bunqueue server?
The server supports clients in Node.js, Deno, Python, PHP, Go, Rust, and Elixir.
Does it support scheduled tasks?
Yes, it includes cron and scheduling capabilities that survive restarts.