
In this article, I want to show you how to implement the factory method pattern in NestJS to allow for cleaner code. By the end of this article, you should be familiar with the factory method pattern & how it can be used in a NestJS application.
Factory Method Pattern
In object oriented programming, the factory method pattern is a design pattern that uses factory methods to deal with the problem of creating objects without having to specify their exact class. Rather than by calling a constructor, this is done by calling a factory method to create an object. Wikipedia
This design pattern will enable us to isolate the responsibility of providing objects to callers using a dedicated method. The objects returned by the factory typically conform to a common interface so the caller knows what properties to expect, but is unaware of the specific implementation (polymorphism).
Use Case
In NestJS, we typically put our application business logic into injectable services. As our application grows & the business logic becomes more complex, the services become too complex and begin to break the single responsibility principle.
The single-responsibility principle (SRP) is a computer programming principle that states that “A module should be responsible to one, and only one, actor.” Wikipedia
In other words – we want our NestJS services to have a single responsibility and avoid becoming a god object, which is a common anti-pattern.
In object-oriented programming, a god object (sometimes also called an omniscient or all-knowing object) is an object that references a large number of distinct types, has too many unrelated or uncategorized methods, or some combination of both. Wikipedia
We can break up our large NestJS services so they are smaller and less complex. However now that we have multiple services, how do we ensure we are supplying the correct one to the caller? This is where the factory method pattern comes into the picture.
Example
You can find the complete code for this example on the GitHub repository here.
In this example, we have a ReportService
that we want to break up into three smaller services that deal with a specific report type. The report type is determined by the report type code which a user can supply.
Each ReportService
implements a common interface so that the caller can treat each one the same – or better known as polymorphism.
export interface ReportService {
submit: () => void;
}
We’ll now declare three ReportServices
that all implement this interface.
import { Injectable, Logger } from '@nestjs/common';
import { ReportService } from '../report-service.interface';
@Injectable()
export class FullReportService implements ReportService {
private readonly logger = new Logger(FullReportService.name);
submit() {
this.logger.log('Submitting full report...');
}
}
import { Injectable, Logger } from '@nestjs/common';
import { ReportService } from '../report-service.interface';
@Injectable()
export class HalfReportService implements ReportService {
private readonly logger = new Logger(HalfReportService.name);
submit() {
this.logger.log('Submitting half report...');
}
}
import { Injectable, Logger } from '@nestjs/common';
import { ReportService } from '../report-service.interface';
@Injectable()
export class EmptyReportService implements ReportService {
private readonly logger = new Logger(EmptyReportService.name);
submit() {
this.logger.log('Submitting empty report...');
}
}
Now that we have three different services it’s time to implement a ReportServiceFactory
that will provide the correct ReportService
depending on the code
provided.
import { Injectable } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { EmptyReportService } from './services/empty-report.service';
import { HalfReportService } from './services/half-report.service';
import { FullReportService } from './services/full-report.service';
@Injectable()
export class ReportServiceFactory {
constructor(private readonly moduleRef: ModuleRef) {}
get(code: string) {
switch (code) {
case 'EMPTY':
return this.moduleRef.get(EmptyReportService);
case 'HALF':
return this.moduleRef.get(HalfReportService);
case 'FULL':
return this.moduleRef.get(FullReportService);
}
}
}
NestJS makes this very easy to do thanks to the injectable ModuleRef
provider. This provider allows us to get access to any provider at runtime simply by providing the injection token, which in this case is the type of service we want.
Finally, we can create a ReportsController
that utilizes the ReportServiceFactory
to call the correct underlying implementation based on the user-provided code
.
import { Controller, Param, Post } from '@nestjs/common';
import { ReportServiceFactory } from './report-service.factory';
@Controller('reports')
export class ReportsController {
constructor(private readonly reportServiceFactory: ReportServiceFactory) {}
@Post(':code/submit')
submitReport(@Param('code') code: string) {
return this.reportServiceFactory.get(code).submit();
}
}
In this controller the report code
is provided as a route parameter and the provided to the ReportServiceFactory
. Lastly, don’t forget to wire up all of these providers & controllers to our application modules
import { Module } from '@nestjs/common';
import { ReportServiceFactory } from './report-service.factory';
import { EmptyReportService } from './services/empty-report.service';
import { HalfReportService } from './services/half-report.service';
import { FullReportService } from './services/full-report.service';
import { ReportsController } from './reports.controller';
@Module({
providers: [
ReportServiceFactory,
EmptyReportService,
HalfReportService,
FullReportService,
],
controllers: [ReportsController],
})
export class ReportsModule {}
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ReportsModule } from './reports/reports.module';
@Module({
imports: [ReportsModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
With this now all in place, we can now call the following endpoints and see the expected logs from each of our services.
- POST http://localhost:3000/reports/FULL/submit
- POST http://localhost:3000/reports/HALF/submit
- POST http://localhost:3000/reports/EMPTY/submit

Now we’ve seen how we can implement the factory method pattern in a NestJS application thanks to the ModuleRef
provider. It is a very useful pattern to help keep our code clean & less complex because we now have the power to break up large services into smaller ones with ease.
Using the Strategy or Command pattern instead of a switch-case statement is a better approach
Thanks so much for the feedback! I think this would make a great additional post.
Romjanali552@gmail.com