Coming from BullMQ
NextMQ runs real BullMQ, so the API you already know mostly just works. The only differences come from your worker running in your app while the queue runs on ours.
Works exactly the same#
Import these from @nextmq/sdk and use them like you always have:
new Queue(),queue.add(),queue.addBulk()new Worker(name, processor, opts)withconcurrencyandlimiterattempts,backoff,delay,priority,lifo,jobId- Job Schedulers —
upsertJobSchedulerand friends FlowProducergraphs with parent/child failure flagsdeduplication, global concurrency and rate limits- Inspection & control —
getJob,getJobCounts,retry,promote,changeDelay,changePriority,updateProgress,log,remove
Works a little differently#
| In BullMQ | In NextMQ |
|---|---|
The Worker runs the job loop in your process | We run the loop and call your processor over a signed webhook. You declare the same processor function. |
Outcome via moveToCompleted / moveToFailed | Return a value to complete, throw to fail. NextMQ maps it for you. |
QueueEvents pub/sub stream | Poll completion with job.waitUntilFinished() — a serverless function can't hold a live stream. |
| Retention defaults to keep-forever | removeOnComplete / removeOnFail are clamped to sane caps so a project can't grow without bound. |
// BullMQ: the worker runs in-process.
// NextMQ: the same processor, declared in your app and run on demand.
export const worker = new Worker('emails', async (job) => {
await send(job.data)
return { ok: true } // return = completed, throw = failed (with retries)
})Not available#
A handful of APIs assume a worker that owns the job in your process, or a payload format that can't cross a network. These aren't supported, and the SDK rejects them clearly rather than failing silently:
- Lock/token APIs —
extendLock,getNextJob,processJob - Manual state moves —
moveToCompleted,moveToFailed,moveToWaitingChildren - Sandboxed/processor-file workers and
useWorkerThreads - In-process
cancelJoband nativeQueueEvents - Non-JSON payloads (binary, class instances)
Tip
Most BullMQ code moves over with no changes beyond the import. If you hit a rejected method, it's one of the items above — and there's a managed equivalent for the common ones (return/throw for outcomes,
waitUntilFinished() for completion).New here instead? Start with the Quickstart.