Creating Background Jobs with NestJS and Bull

@rnab
3 min readJan 5, 2025

--

In modern web applications, offloading tasks to background jobs can substantially improve performance and enhance user experience. NestJS, a progressive Node.js framework, when combined with Bull (a robust Redis-based queue), provides a powerful solution for managing background jobs. This article will guide you through setting up and using Bull to manage background jobs in a NestJS application. We’ll build a simple example to illustrate the concepts.

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Setting up NestJS Project
  4. Installing Required Packages
  5. Configuring Redis
  6. Creating a Bull Queue
  7. Creating and Processing Jobs
  8. Running the Application
  9. Conclusion

1. Introduction

Background jobs are tasks executed outside of the main user interaction flow, improving performance by allowing resource-heavy tasks to be processed asynchronously. Examples include sending emails, resizing images, or cleaning up databases. Bull provides a feature-rich library to manage these jobs with Redis as the underlying data store.

2. Prerequisites

Before diving in, ensure you have the following installed:

  • Node.js (>= 12.x)
  • npm (>= 6.x) or yarn
  • Redis server

3. Setting up NestJS Project

First, create a new NestJS project:

$ nest new nest-bull-example
$ cd nest-bull-example

4. Installing Required Packages

Next, install @nestjs/bull, bull, and @nestjs/queues:

$ npm install @nestjs/bull bull

5. Configuring Redis

Bull uses Redis to manage its job queues. Ensure Redis is running on your local machine or remote server. By default, Redis runs on port 6379. Configure it in your NestJS application.

In your app.module.ts, import BullModule and configure it to connect to your Redis server:

import { Module } from '@nestjs/common';
import { BullModule } from '@nestjs/bull';
import { BullService } from './bull.service';
import { BullProcessor } from './bull.processor';

@Module({
imports: [
BullModule.forRoot({
redis: {
host: 'localhost', // Use your Redis server host
port: 6379,
},
}),
BullModule.registerQueue({
name: 'emailQueue',
}),
],
providers: [BullService, BullProcessor],
})
export class AppModule {}

6. Creating a Bull Queue

Create a service that will handle job creation. Create bull.service.ts:

import { Injectable } from '@nestjs/common';
import { InjectQueue } from '@nestjs/bull';
import { Queue } from 'bull';

@Injectable()
export class BullService {
constructor(
@InjectQueue('emailQueue') private readonly emailQueue: Queue,
) {}

async addEmailJob(email: string, content: string) {
await this.emailQueue.add('sendEmail', {
email,
content,
});
}
}

7. Creating and Processing Jobs

Create a processor that will handle jobs as they are added to the queue. Create bull.processor.ts:

import { Process, Processor } from '@nestjs/bull';
import { Job } from 'bull';

@Processor('emailQueue')
export class BullProcessor {
@Process('sendEmail')
async handleSendEmailJob(job: Job) {
const { email, content } = job.data;
console.log(`Sending email to: ${email}, content: ${content}`);
// Here, you can integrate an email service to send actual emails
}
}

8. Running the Application

Now, let’s create a controller to trigger job addition. Create bull.controller.ts:

import { Controller, Post, Body } from '@nestjs/common';
import { BullService } from './bull.service';

@Controller('email')
export class BullController {
constructor(private readonly bullService: BullService) {}

@Post()
async sendEmail(@Body() body: { email: string; content: string }) {
await this.bullService.addEmailJob(body.email, body.content);
return { message: 'Email job added to the queue' };
}
}

Finally, add this controller to your module:

import { Module } from '@nestjs/common';
import { BullModule } from '@nestjs/bull';
import { BullService } from './bull.service';
import { BullProcessor } from './bull.processor';
import { BullController } from './bull.controller';

@Module({
imports: [
BullModule.forRoot({
redis: {
host: 'localhost',
port: 6379,
},
}),
BullModule.registerQueue({
name: 'emailQueue',
}),
],
providers: [BullService, BullProcessor],
controllers: [BullController],
})
export class AppModule {}

Start the application and test the API endpoint:

$ npm run start

You can use Postman or curl to POST to /email with the following JSON body:

{
"email": "example@example.com",
"content": "Welcome to our service!"
}

Observe the console for job processing logs.

9. Conclusion

In this article, you’ve learned how to integrate Bull with NestJS to manage background jobs efficiently. This approach ensures your application remains performant and responsive by offloading resource-intensive operations to background workers. You can further extend this setup by integrating various services like email providers, image processing libraries, and more.

Happy coding! 🛠️

--

--

@rnab
@rnab

Written by @rnab

Typescript, Devops, Kubernetes, AWS, AI/ML, Algo Trading

No responses yet