Lazy Loading in NestJS: Boosting Performance and Efficiency
Lazy loading is a powerful design pattern that delays the initialization of resources until they are actually needed. This can significantly enhance the performance and resource management of your application. In NestJS, lazy loading can be implemented using dynamic modules and the LazyModuleLoader
from @nestjs/core
. This article explores both methods, providing detailed examples to help you implement lazy loading in your NestJS applications.
Why Lazy Loading?
Lazy loading helps in:
- Reducing Initial Load Time: By not loading everything at startup, the application can start faster.
- Optimizing Resource Usage: Only load the components or modules when they are actually needed.
- Improving Scalability: Efficient use of resources can help the application scale better.
Using LazyModuleLoader for Lazy Loading
To implement lazy loading in NestJS we useLazyModuleLoader
from @nestjs/core
.
Step 1: Create the Module to be Lazy Loaded
Create the ReportsModule
similarly as before.
// reports.module.ts
import { Module } from '@nestjs/common';
import { ReportsService } from './reports.service';
import { ReportsController } from './reports.controller';
@Module({
controllers: [ReportsController],
providers: [ReportsService],
})
export class ReportsModule {}
Step 2: Create the Service for the Lazy Loaded Module
Define the service for the ReportsModule
.
// reports.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class ReportsService {
getReport(): string {
console.log('lazily loaded reports module');
return 'This is a report!';
}
}
Step 3: Define the Main Module
Define the AppModule without importing ReportsModule as we will import it later lazilly.
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Step 4: Create a Controller to Handle Lazy Loading and Other Logic
Create a controller that uses LazyModuleLoader
to load the ReportsModule
dynamically.
// app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { LazyModuleLoader } from '@nestjs/core';
import { ReportsModule } from './reports/reports.module';
import { ReportsService } from './reports/reports.service';
@Controller()
export class AppController {
constructor(private readonly lazyModuleLoader: LazyModuleLoader) {}
@Get()
async getLazyReport(): Promise<string> {
// use console.time() and console.timeEnd()
//to get the initialization time of ReportsModule
console.time();
const moduleRef = await this.lazyModuleLoader.load(() => ReportsModule);
const reportsService = moduleRef.get(ReportsService);
console.timeEnd();
return reportsService.getReport();
}
}
Example Usage
When the first request is made to the endpoint, the ReportsModule
will be loaded lazily, and the ReportsService
will handle the request, returning a report.
$ curl http://localhost:3000/lazy-reports
This is a report!
And if you made more requests each consecutive attempt to load ReportsModule
is much faster the load method returns a cached instance of the module.
Making more than one request you will see output like this in app logs.
default: 6.226ms
lazily loaded reports module
[Nest] 208649 - 05/26/2024, 8:33:22 PM LOG [LazyModuleLoader] ReportsModule dependencies initialized
default: 2.323ms
lazily loaded reports module
[Nest] 208649 - 05/26/2024, 8:33:22 PM LOG [LazyModuleLoader] ReportsModule dependencies initialized
default: 2.012ms
lazily loaded reports module
Conclusion
Implementing lazy loading in NestJS can significantly enhance the performance and resource efficiency of your application.
Using LazyModuleLoader
in NestJS ensures that modules are loaded lazily once for first time and cached, optimizing performance and resource usage. This approach helps manage dynamic module loading efficiently, providing a balance between initial load time and runtime efficiency.