avifenesh/glide-mq/glide-mq-migrate-bullmq

Claude Code and agent skill by avifenesh/glide-mq

Trust tier 2
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Use when moving a Node.js project from BullMQ (or BullMQ Pro groups) to glide-mq, or comparing the two APIs: connection format, changed signatures, removed options, and what replaces them.

Install

npx vskill@latest install avifenesh/glide-mq/glide-mq-migrate-bullmq

SKILL.md

Migrate from BullMQ to glide-mq

The glide-mq API is intentionally similar to BullMQ. Most of a migration is the connection format and imports; the table below lists every change that breaks code, and the steps show each conversion. Work through them in order, then run the project's tests.

Prerequisites

  • Node.js 20+
  • Valkey 7.0+ or Redis 7.0+ (both supported)
  • TypeScript 5+ recommended

Install

bash
npm remove bullmq
npm install glide-mq
ts
// Before
import { Queue, Worker, Job, QueueEvents, FlowProducer } from 'bullmq';
// After
import { Queue, Worker, Job, QueueEvents, FlowProducer } from 'glide-mq';

Breaking changes

FeatureBullMQglide-mq
Connection config{ host, port }{ addresses: [{ host, port }] }
TLStls: {}useTLS: true
Passwordpassword: 'secret'credentials: { password: 'secret' }
Cluster modeImplicit / natMapclusterMode: true
`defaultJobOptions`On QueueOptionsRemoved - wrap queue.add() with defaults
`queue.getJobs()`Accepts array of typesSingle type per call
`queue.getJobCounts()`Variadic type listAlways returns all states
`settings.backoffStrategy`Single functionbackoffStrategies named map on WorkerOptions
`worker.on('active')`Emits (job, prev)Emits (job, jobId)
`job.waitUntilFinished()`(queueEvents, ttl), resolves to the result(pollIntervalMs, timeoutMs), resolves to 'completed' or 'failed'
Sandboxed processoruseWorkerThreads: truesandbox: { useWorkerThreads: true }
`QueueScheduler`Required in v1, optional in v2+Does not exist - promotion runs inside Worker
`opts.repeat`On queue.add()Removed - use queue.upsertJobScheduler()
FlowJob `data`OptionalRequired
`retries-exhausted` eventSeparate QueueEvents eventCheck attemptsMade >= opts.attempts in 'failed'
BullMQ Pro `group.id`group: { id } (Pro license)ordering: { key } (open source)
Group concurrencygroup.limit.max (Pro)ordering: { key, concurrency: N }
Group rate limitgroup.limit (Pro)ordering: { key, rateLimit: { max, duration } }

Step-by-step conversion

1. Connection config (the biggest change)
ts
// BEFORE (BullMQ)
const connection = { host: 'localhost', port: 6379 };
ts
// AFTER (glide-mq)
const connection = { addresses: [{ host: 'localhost', port: 6379 }] };

For TLS + password + cluster, see references/connection-mapping.md.

2. Queue.add - identical API
ts
// BEFORE
const queue = new Queue('tasks', { connection });
await queue.add('send-email', { to: 'user@example.com' });
ts
// AFTER - only the connection changes
const queue = new Queue('tasks', { connection });
await queue.add('send-email', { to: 'user@example.com' });
3. Worker - identical API, different connection
ts
// BEFORE
const worker = new Worker(
'tasks',
async (job) => {
await sendEmail(job.data.to);
},
{ connection: { host: 'localhost', port: 6379 }, concurrency: 10 },
);
ts
// AFTER
const worker = new Worker(
'tasks',
async (job) => {
await sendEmail(job.data.to);
},
{ connection: { addresses: [{ host: 'localhost', port: 6379 }] }, concurrency: 10 },
);
4. FlowProducer - identical API
ts
// Both - same usage, only connection format differs
const flow = new FlowProducer({ connection });
await flow.add({
name: 'parent',
queueName: 'tasks',
data: { step: 'final' }, // NOTE: data is required in glide-mq
children: [
{ name: 'child-1', queueName: 'tasks', data: { step: '1' } },
{ name: 'child-2', queueName: 'tasks', data: { step: '2' } },
],
});
5. QueueEvents - identical API
ts
// Both - same, only connection format differs
const qe = new QueueEvents('tasks', { connection });
qe.on('completed', ({ jobId }) => console.log(jobId, 'done'));
qe.on('failed', ({ jobId, failedReason }) => console.error(jobId, failedReason));

Note: some BullMQ events are not yet emitted. See Current gaps.

6. Graceful shutdown
ts
// BullMQ
await worker.close();
await queue.close();
ts
// glide-mq - identical
await worker.close();
await queue.close();
7. UnrecoverableError - identical
ts
// Both
import { UnrecoverableError } from 'glide-mq'; // was 'bullmq'
throw new UnrecoverableError('permanent failure');
8. Scheduling (repeatable jobs)
ts
// BEFORE - opts.repeat (deprecated in BullMQ v5)
await queue.add('report', data, {
repeat: { pattern: '0 9 * * *', tz: 'America/New_York' },
});
ts
// AFTER - upsertJobScheduler
await queue.upsertJobScheduler(
'report',
{ pattern: '0 9 * * *', tz: 'America/New_York' },
{ name: 'report', data: { v: 1 } },
);
9. Custom backoff strategies
ts
// BEFORE
const worker = new Worker('q', processor, {
connection,
settings: {
backoffStrategy: (attemptsMade, type, delay, err) => {
if (type === 'jitter') return delay + Math.random() * delay;
return delay * attemptsMade;
},
},
});
ts
// AFTER
const worker = new Worker('q', processor, {
connection,
backoffStrategies: {
jitter: (attemptsMade, err) => 1000 + Math.random() * 1000,
linear: (attemptsMade, err) => 1000 * attemptsMade,
},
});
10. defaultJobOptions removal
ts
// BEFORE
const queue = new Queue('tasks', {
connection,
defaultJobOptions: { attempts: 3, backoff: { type: 'exponential', delay: 1000 } },
});
ts
// AFTER - wrap add() with your defaults
const DEFAULTS = { attempts: 3, backoff: { type: 'exponential', delay: 1000 } } as const;
const add = (name: string, data: unknown, opts?: JobOptions) => queue.add(name, data, { ...DEFAULTS, ...opts });
11. getJobs with multiple types
ts
// BEFORE
const jobs = await queue.getJobs(['waiting', 'active'], 0, 99);
ts
// AFTER
const [waiting, active] = await Promise.all([queue.getJobs('waiting', 0, 99), queue.getJobs('active', 0, 99)]);
const jobs = [...waiting, ...active];
12. job.waitUntilFinished
ts
// BEFORE
const qe = new QueueEvents('tasks', { connection });
const result = await job.waitUntilFinished(qe, 30000);
ts
// AFTER - no QueueEvents needed
const state = await job.waitUntilFinished(500, 30000);
// args: pollIntervalMs (default 500), timeoutMs (default 30000)
// resolves to 'completed' or 'failed'; read the result with queue.getJob(job.id)
// or use queue.addAndWait() when you need the return value
13. BullMQ Pro groups to ordering keys
ts
// BEFORE (BullMQ Pro)
await queue.add('job', data, {
group: { id: 'tenant-123', limit: { max: 2, duration: 0 } },
});
ts
// AFTER (glide-mq, open source)
await queue.add('job', data, {
ordering: { key: 'tenant-123', concurrency: 2 },
});

What's new in glide-mq (not in BullMQ)

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
80
Repository forks
1
Repository npm downloads, 7 days
242
7-day trend score
37

Stars and forks are for the whole GitHub repository, not this skill alone. Downloads are for the repository's npm package. Refreshed 30 Apr 2026, 6 months ago.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/avifenesh/glide-mq/glide-mq-migrate-bullmq/badge)](https://verified-skill.com/skills/avifenesh/glide-mq/glide-mq-migrate-bullmq)

Something wrong with this skill or its page? Tell us.