Sling Academy
Home/Node.js/How to Use Async Local Storage in NestJS

How to Use Async Local Storage in NestJS

Last updated: December 31, 2023

Introduction

Async local storage in NestJS enables scope-bound storage, allowing you to maintain context across asynchronous operations. It’s essential in tracing requests and handling per-request data without passing parameters around.

Setting Up Async Local Storage

To begin, install the necessary packages:

npm install @nestjs/common @nestjs/core reflect-metadata

Then, set up the async local storage middleware:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AsyncLocalStorage } from 'async_hooks';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const asyncLocalStorage = new AsyncLocalStorage();
  app.use((req, res, next) => {
    asyncLocalStorage.run(new Map(), () => {
      next();
    });
  });
  await app.listen(3000);
}
bootstrap();

Injecting and Using the Storage

Here’s how you can inject and use the storage:

import { Injectable, Scope } from '@nestjs/common';
import { AsyncLocalStorage } from 'async_hooks';

@Injectable({ scope: Scope.REQUEST })
export class MyService {
  constructor(private asyncLocalStorage: AsyncLocalStorage) {}

  myMethod() {
    const store = this.asyncLocalStorage.getStore();
    // Use the store
  }
}

Providing Context

To provide context for dependencies, use interceptors or middleware:

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { AsyncLocalStorage } from 'async_hooks';

@Injectable()
export class ContextInterceptor implements NestInterceptor {
  constructor(private asyncLocalStorage: AsyncLocalStorage) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable {
    const ctx = this.asyncLocalStorage.getStore();
    if (ctx) {
      ctx.set('key', 'value');
    }
    return next.handle();
  }
}

Advanced Usage: Per-Request Providers

Create providers that are new for each request like this:

import { REQUEST } from '@nestjs/core';
import { Provider } from '@nestjs/common';

export const myRequestProvider: Provider = {
  provide: 'MY_PROVIDER',
  useFactory: (request) => new MyProvider(request),
  inject: [REQUEST],
};

Integrating with Other Modules

To integrate async local storage with other modules:

import { DynamicModule, Module } from '@nestjs/common';
import { MyService } from './my.service';

@Module({})
export class MyModule {
  static forRoot(): DynamicModule {
    return {
      module: MyModule,
      providers: [
        {
          provide: 'ASYNC_CONTEXT',
          useClass: MyService,
        },
      ],
      exports: ['ASYNC_CONTEXT'],
    };
  }
}

This way, you’d be able to inject ‘ASYNC_CONTEXT’ as needed across your application.

Conclusion

Async local storage is a powerful feature that helps maintain a coherent state across asynchronous calls in NestJS applications. By following this guide, you’ve learned how to set up, use and integrate async local storage into your NestJS projects. Remember to use this feature judiciously to avoid memory leaks and ensure context-correct operations.

Next Article: How to Write Unit Tests in NestJS with Jest and Supertest

Previous Article: How to Use Sequelize ORM in NestJS

Series: Nest.js Tutorials: From Basics to Advanced

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates