Home
NestJS
NestJS - Dependency Injection
September 06, 2023
1 min

Table Of Contents

01
πŸš€ Dependency Injection in NestJS β€” Quick Guide with Intro + Example for Each
02
🧠 1. What is Dependency Injection?
03
πŸ—οΈ 2. Control NestJS Module Encapsulation
04
πŸ”§ 3. Custom Providers
05
πŸ“¦ 4. Value-based Providers (useValue)
06
πŸ”‘ 5. Non-class-based Provider Tokens
07
🧱 6. Class Providers (useClass)
08
βš™οΈ 7. Factory Providers (useFactory)
09
⚑ 8. Async Providers
10
🧩 9. Dynamic Modules
11
πŸ” 10. Request-Scoped Providers
12
🎯 Final Thought

πŸš€ Dependency Injection in NestJS β€” Quick Guide with Intro + Example for Each


🧠 1. What is Dependency Injection?

πŸ‘‰ Introduction: Dependency Injection lets NestJS create and provide dependencies instead of you manually instantiating them.

@Injectable()
export class UsersService {
findAll() {
return ['user1', 'user2'];
}
}
@Controller('users')
export class UsersController {
constructor(private usersService: UsersService) {}
@Get()
getUsers() {
return this.usersService.findAll();
}
}

πŸ‘‰ Explanation: NestJS automatically creates UsersService and injects it into the controller.


πŸ—οΈ 2. Control NestJS Module Encapsulation

πŸ‘‰ Introduction: Modules control which providers are private or shared across the app.

@Module({
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
@Module({
imports: [UsersModule],
providers: [OrdersService],
})
export class OrdersModule {}

πŸ‘‰ Explanation: UsersService is accessible in OrdersModule because it is exported.


πŸ”§ 3. Custom Providers

πŸ‘‰ Introduction: Custom providers allow you to define exactly how a dependency is created.

@Module({
providers: [
{
provide: 'HELLO_MESSAGE',
useValue: 'Hello DI',
},
],
})
export class AppModule {}
@Injectable()
export class HelloService {
constructor(@Inject('HELLO_MESSAGE') private message: string) {}
getMessage() {
return this.message;
}
}

πŸ‘‰ Explanation: You manually define what gets injected using a custom token.


πŸ“¦ 4. Value-based Providers (useValue)

πŸ‘‰ Introduction: Value providers inject static data into your application.

@Module({
providers: [
{
provide: 'CONFIG',
useValue: {
defaultLimit: 10,
},
},
],
})
export class AppModule {}
@Injectable()
export class UsersService {
constructor(@Inject('CONFIG') private config) {}
getLimit() {
return this.config.defaultLimit;
}
}

πŸ‘‰ Explanation: Useful for config or constants without logic.


πŸ”‘ 5. Non-class-based Provider Tokens

πŸ‘‰ Introduction: Tokens don’t have to be classesβ€”they can be strings or symbols.

export const CONFIG_TOKEN = Symbol('CONFIG');
@Module({
providers: [
{
provide: CONFIG_TOKEN,
useValue: { limit: 20 },
},
],
})
export class AppModule {}
@Injectable()
export class UsersService {
constructor(@Inject(CONFIG_TOKEN) private config) {}
}

πŸ‘‰ Explanation: Symbols prevent naming conflicts in large apps.


🧱 6. Class Providers (useClass)

πŸ‘‰ Introduction: Class providers let you swap implementations for the same dependency.

@Injectable()
export class MockUsersService {
findAll() {
return ['mock-user'];
}
}
@Module({
providers: [
{
provide: UsersService,
useClass: MockUsersService,
},
],
})
export class AppModule {}
@Controller('users')
export class UsersController {
constructor(private usersService: UsersService) {}
@Get()
getUsers() {
return this.usersService.findAll();
}
}

πŸ‘‰ Explanation: Controller still injects UsersService, but gets MockUsersService.


βš™οΈ 7. Factory Providers (useFactory)

πŸ‘‰ Introduction: Factory providers create dependencies using a function.

@Module({
providers: [
{
provide: 'RANDOM_NUMBER',
useFactory: () => Math.random(),
},
],
})
export class AppModule {}
@Injectable()
export class RandomService {
constructor(@Inject('RANDOM_NUMBER') private num: number) {}
getNumber() {
return this.num;
}
}

πŸ‘‰ Explanation: The value is generated dynamically when injected.


⚑ 8. Async Providers

πŸ‘‰ Introduction: Async providers allow dependencies to be initialized asynchronously.

@Module({
providers: [
{
provide: 'ASYNC_DATA',
useFactory: async () => {
return new Promise((resolve) =>
setTimeout(() => resolve('Loaded'), 1000),
);
},
},
],
})
export class AppModule {}
@Injectable()
export class DataService {
constructor(@Inject('ASYNC_DATA') private data: string) {}
}

πŸ‘‰ Explanation: Nest waits for async data before starting the app.


🧩 9. Dynamic Modules

πŸ‘‰ Introduction: Dynamic modules allow you to configure a module when importing it.

@Module({})
export class ConfigModule {
static forRoot(options): DynamicModule {
return {
module: ConfigModule,
providers: [
{ provide: 'CONFIG', useValue: options },
],
exports: ['CONFIG'],
};
}
}
@Module({
imports: [ConfigModule.forRoot({ port: 3000 })],
})
export class AppModule {}
@Injectable()
export class AppService {
constructor(@Inject('CONFIG') private config) {}
}

πŸ‘‰ Explanation: Config is passed at import time and injected anywhere.


πŸ” 10. Request-Scoped Providers

πŸ‘‰ Introduction: Request-scoped providers create a new instance for each request.

@Injectable({ scope: Scope.REQUEST })
export class RequestContextService {
constructor(@Inject(REQUEST) private req: Request) {}
getUser() {
return this.req.user;
}
}
@Injectable()
export class UsersService {
constructor(private ctx: RequestContextService) {}
getCurrentUser() {
return this.ctx.getUser();
}
}

πŸ‘‰ Explanation: Each request gets its own instance, allowing access to request-specific data.


🎯 Final Thought

Dependency Injection in NestJS is the foundation of:

  • Clean architecture
  • Flexible systems
  • Scalable applications

Master it, and you move from writing code β†’ designing systems.


Tags

#NestJS

Share

Related Posts

NextJS
NestJS - Setup with PostgreSQL & Docker
September 06, 2023
1 min
Β© 2026, All Rights Reserved.
Powered By

Social Media

githublinkedinyoutube