Skip to content

Migration from BullMQ

This guide helps you migrate from BullMQ to bunqueue with minimal code changes.

Overview

bunqueue provides a BullMQ-compatible API, making migration straightforward for most use cases.

BullMQbunqueueNotes
new Queue()new Queue()✅ Same API
new Worker()new Worker()✅ Same API
QueueEventsQueueEvents✅ Same API
FlowProducerFlowProducer✅ Same API
jobId deduplicationjobId deduplication✅ Same behavior (idempotent)
Redis connectionNot needed✅ Simpler

Step 1: Install bunqueue

Terminal window
# Remove BullMQ and Redis
bun remove bullmq ioredis
# Install bunqueue
bun add bunqueue

Step 2: Update Imports

// Before (BullMQ)
import { Queue, Worker, QueueEvents } from 'bullmq';
import Redis from 'ioredis';
const connection = new Redis();
const queue = new Queue('my-queue', { connection });
// After (bunqueue)
import { Queue, Worker, QueueEvents } from 'bunqueue/client';
const queue = new Queue('my-queue', { embedded: true });
// No connection needed - uses in-process SQLite!

Step 3: Remove Redis Configuration

// Before (BullMQ)
const queue = new Queue('emails', {
connection: {
host: 'localhost',
port: 6379,
password: 'secret',
},
defaultJobOptions: {
attempts: 3,
backoff: { type: 'exponential', delay: 1000 },
},
});
// After (bunqueue)
const queue = new Queue('emails', {
embedded: true,
defaultJobOptions: {
attempts: 3,
backoff: 1000, // Base delay for exponential backoff
},
});

Step 4: Update Worker

// Before (BullMQ)
const worker = new Worker('emails', async (job) => {
await sendEmail(job.data);
return { sent: true };
}, {
connection,
concurrency: 5,
limiter: { max: 100, duration: 1000 },
});
// After (bunqueue)
const worker = new Worker('emails', async (job) => {
await sendEmail(job.data);
return { sent: true };
}, {
embedded: true,
concurrency: 5,
// Rate limiting is set on queue via server mode, not worker
});
// Rate limiting is configured via CLI or TCP server
// bunqueue rate-limit set emails 100

Step 5: Update Events

Events work the same way:

// Same in both BullMQ and bunqueue
worker.on('completed', (job, result) => {
console.log(`Job ${job.id} completed`);
});
worker.on('failed', (job, err) => {
console.error(`Job ${job.id} failed:`, err.message);
});
worker.on('progress', (job, progress) => {
console.log(`Job ${job.id}: ${progress}%`);
});

Step 6: Update Job Options

// Before (BullMQ)
await queue.add('task', data, {
priority: 1,
delay: 5000,
attempts: 3,
backoff: { type: 'exponential', delay: 1000 },
removeOnComplete: true,
removeOnFail: false,
jobId: 'custom-id',
});
// After (bunqueue) - Almost identical
// Queue created with: new Queue('tasks', { embedded: true })
await queue.add('task', data, {
priority: 1,
delay: 5000,
attempts: 3,
backoff: 1000, // Base delay (exponential: 1s, 2s, 4s, 8s...)
removeOnComplete: true,
removeOnFail: false,
jobId: 'custom-id',
});

API Differences

Backoff Configuration

// BullMQ supports both types
backoff: { type: 'exponential', delay: 1000 }
backoff: { type: 'fixed', delay: 5000 }
// bunqueue only supports exponential backoff
backoff: 1000 // Base delay in ms

Rate Limiting

// BullMQ (on worker)
new Worker('queue', processor, {
limiter: { max: 100, duration: 1000 }
});
// bunqueue (server mode only - via CLI or TCP)
// Rate limiting is not available in embedded mode
bunqueue rate-limit set my-queue 100

Sandboxed Processors

// BullMQ sandboxed processors
new Worker('queue', './processor.js', { connection });
// bunqueue SandboxedWorker (isolated Bun Worker processes)
import { SandboxedWorker } from 'bunqueue/client';
const worker = new SandboxedWorker('queue', {
processor: './processor.ts',
concurrency: 4,
timeout: 30000,
});
worker.start();

Repeatable Jobs

// BullMQ
await queue.add('task', data, {
repeat: { cron: '0 * * * *' }
});
// bunqueue (queue created with embedded: true)
await queue.add('task', data, {
repeat: { pattern: '0 * * * *' }
});
// Or use interval
await queue.add('task', data, {
repeat: { every: 3600000 }
});

Features Comparison

FeatureBullMQbunqueueNotes
Sandboxed processorsUse SandboxedWorker
Redis ClusterSingle instance
Redis StreamsSQLite storage
Rate limit per workerQueue-level rate limit

Migration Checklist

  • Remove bullmq and ioredis packages
  • Install bunqueue
  • Update imports to bunqueue/client
  • Remove all Redis connection configuration
  • Update backoff configuration (simplified)
  • Move rate limiting from worker to queue
  • Update sandboxed processors to use SandboxedWorker
  • Update repeat config (cronpattern)
  • Test all job processing
  • Remove Redis server from infrastructure

Getting Help

If you encounter issues during migration: