Next.js starter your AI actually understands. Ship internal tools in days not weeks. Pre-order $199 $499 → [Get it now]

How to queue background jobs in Node.js

Background job queues decouple time-consuming tasks — sending emails, processing images, generating reports — from the HTTP request cycle, keeping API responses fast and reliable. As the creator of CoreUI with 25 years of backend development experience, I’ve implemented job queues in Node.js applications where processing tasks synchronously caused request timeouts and poor user experience. BullMQ with Redis is the standard solution: jobs are enqueued instantly, workers process them asynchronously with retry, priority, and scheduling support. This architecture lets you return 202 Accepted immediately and process the work in the background.

Install BullMQ and set up a queue with a worker.

npm install bullmq redis ioredis
// src/queues/email.queue.js
import { Queue, Worker, QueueEvents } from 'bullmq'

const connection = {
  host: process.env.REDIS_HOST ?? 'localhost',
  port: Number(process.env.REDIS_PORT ?? 6379)
}

// Create the queue
export const emailQueue = new Queue('email', { connection })

// Create a worker that processes jobs from the queue
const emailWorker = new Worker(
  'email',
  async (job) => {
    const { to, subject, body } = job.data
    console.log(`Sending email to ${to}: ${subject}`)

    // Simulate sending email
    await sendEmail({ to, subject, body })

    return { sent: true, to, timestamp: new Date().toISOString() }
  },
  {
    connection,
    concurrency: 5 // Process up to 5 jobs simultaneously
  }
)

emailWorker.on('completed', (job, result) => {
  console.log(`Email job ${job.id} completed:`, result)
})

emailWorker.on('failed', (job, err) => {
  console.error(`Email job ${job.id} failed:`, err.message)
})

The Queue accepts jobs and the Worker processes them. Both connect to the same Redis instance. concurrency: 5 runs up to 5 email jobs in parallel, maximizing throughput while respecting your email provider’s rate limits.

Adding Jobs to the Queue

Enqueue jobs from route handlers.

// src/routes/auth.router.js
import { Router } from 'express'
import { emailQueue } from '../queues/email.queue.js'

const router = Router()

router.post('/register', async (req, res, next) => {
  try {
    const user = await createUser(req.body)

    // Enqueue welcome email - returns immediately
    await emailQueue.add(
      'welcome-email',
      { to: user.email, subject: 'Welcome!', body: `Hello ${user.name}` },
      {
        attempts: 3,          // Retry up to 3 times on failure
        backoff: {
          type: 'exponential',
          delay: 5000         // 5s, 10s, 20s delays
        },
        removeOnComplete: 100, // Keep last 100 completed jobs
        removeOnFail: 50       // Keep last 50 failed jobs
      }
    )

    res.status(201).json({ id: user.id })
  } catch (err) {
    next(err)
  }
})

emailQueue.add() is fast — it just writes to Redis and returns. The actual email sending happens in the worker process, decoupled from the HTTP response.

Scheduled and Delayed Jobs

Schedule jobs to run at a specific time or after a delay.

// Send a reminder email in 24 hours
await emailQueue.add(
  'reminder',
  { to: user.email, subject: 'Reminder', body: 'You have unread notifications' },
  { delay: 24 * 60 * 60 * 1000 } // 24 hours in milliseconds
)

// Run every day at 9am (cron syntax)
await emailQueue.add(
  'daily-digest',
  { type: 'digest' },
  { repeat: { cron: '0 9 * * *' } }
)

Delayed and repeating jobs are managed entirely by BullMQ — no setInterval or cron process needed. Redis stores the schedule and BullMQ triggers the job at the right time.

Best Practice Note

This is the same queue architecture used in CoreUI backend templates for notifications and async processing. Run workers in separate Node.js processes (not in the same process as the HTTP server) so a crashed worker doesn’t take down the API. Use the BullMQ Dashboard or Bull Board for a web UI to monitor queue status, retry failed jobs, and inspect job data. See how to build a notification service in Node.js for an end-to-end example using queues for push notifications.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author