NextMQ

How it works

You write a queue and a processor. NextMQ runs the BullMQ server and Redis, schedules the work, and calls your processor back over a signed webhook.

How a job flows
Your Next.js app
Pages
Route handlers
Server actions
NextMQ SDK
BullMQ-API-compatible
add job
run job
NextMQ
BullMQ server
real workers
Redis
jobs & state

The SDK lives in your app and talks to NextMQ over HTTPS.

Your side#

@nextmq/sdk gives you the BullMQ-shaped Queue, Worker, and FlowProducer classes. There's no Redis connection in your app. Calling queue.add() sends an authenticated request to NextMQ. A Worker declares the processor function that should run when a job is triggered.

The one piece of plumbing you add is a webhook route built with createNextMQHandler. It verifies every signed request, registers your workers and dispatches incoming jobs.

Our side#

NextMQ runs the real BullMQ Queue and Worker instances against a managed Redis. We own the scheduler, lock handling, retries, backoff, delays, priority, concurrency, and rate limiting. Your jobs and their state are stored durably and isolated to your project.

Note
Job data, progress, logs, return values, errors, and state live in NextMQ storage. Your processor source code and server secrets stay in your app; NextMQ calls them over the signed webhook route.

The lifecycle of a job#

  1. Enqueue. Your route calls queue.add(); the SDK sends it to NextMQ, which stores the job.
  2. Schedule. Our BullMQ worker applies delay, priority, and rate limits, then picks the job up when it's due.
  3. Dispatch. NextMQ signs the job and calls your webhook route.
  4. Process. The handler verifies the signature and runs your processor function.
  5. Finalize. We read your response and mark the job completed, failed (with retries/backoff), or rate-limited.

Why a webhook instead of a local worker#

A BullMQ worker needs a blocking Redis connection and timers that run continuously — which a serverless function, frozen between requests, can't hold. So that loop lives on our side, and your app only needs to be reachable for one request → one result. This is also why a few BullMQ APIs differ here; see Coming from BullMQ.