NextMQ

Quickstart

From zero to a working background job in a Next.js app. There's no server or Redis to set up — that's the part we manage.

Prerequisites#

1. Create a project#

Sign up and create a project in the NextMQ dashboard. You'll get one connection string — it bundles your server URL, API key, and webhook secret. Keep it handy for the next step.

2. Install the SDK#

npm install @nextmq/sdk

3. Add your environment#

Paste the connection string from your dashboard, plus your app's public URL.

.env.local
NEXTMQ_CONNECTION_STRING=nextmq://v1....
NEXT_PUBLIC_APP_URL=https://your-app.com

NEXT_PUBLIC_APP_URL is where NextMQ calls back to run your jobs. Keep the connection string server-only — it's a secret.

4. Define a queue and a worker#

The same primitives as BullMQ. The processor is the code NextMQ calls back to run.

jobs/images.ts
import { Queue, Worker } from '@nextmq/sdk'

export const imageQueue = new Queue<{ uploadId: string }>('images')

export const imageWorker = new Worker('images', async (job) => {
  await job.updateProgress(25)
  const thumb = await makeThumbnail(job.data.uploadId)
  return { thumbnailUrl: thumb.url }
})

async function makeThumbnail(uploadId: string) {
  // Replace with your image pipeline.
  return { url: `https://cdn.example.com/thumbs/${uploadId}.jpg` }
}

5. Add the webhook route#

One catch-all route handles every queue. It verifies signatures, dispatches jobs to the right worker, and exposes a /health path. It must run on the Node.js runtime.

app/api/nextmq/[...path]/route.ts
import { createNextMQHandler } from '@nextmq/sdk/next'
import { imageWorker } from '@/jobs/images'

export const runtime = 'nodejs'

export const { GET, POST } = createNextMQHandler({
  workers: [imageWorker],
})

6. Enqueue a job#

From a route handler or server action:

app/api/upload/route.ts
import { imageQueue } from '@/jobs/images'

export async function POST(req: Request) {
  const { uploadId } = await req.json()

  const job = await imageQueue.add('thumbnail', { uploadId }, {
    attempts: 5,
    backoff: { type: 'exponential', delay: 1000 },
  })

  return Response.json({ queued: true, jobId: job.id })
}

7. See it run#

Open the dashboard and look at the images queue, or wait for the result when the job is short enough for the original request to stay open.

const job = await imageQueue.add('thumbnail', { uploadId })
const result = await job.waitUntilFinished({
  timeoutMs: 15_000,
  pollIntervalMs: 500,
})

What happens now#

NextMQ stores the job, a real BullMQ worker picks it up, and it calls your /api/nextmq route to run imageWorker. If your processor throws, NextMQ retries with exponential backoff up to five attempts — no extra code from you.

Keep going#