2026. 5. 4.·base·
NestJS의 커스텀 프로바이더 선언 (Class Provider)
nodejs 백엔드 개념
// logs/logs.module.ts
@Module({
providers: [
{ provide: LogsRepository, useClass: InMemoryLogsRepository },
],
exports: [LogsRepository],
})
export class LogsModule {}
위와 같은 문법은 NestJS나 Angular와 같은 의존성 주입 프레임워크에서 사용하는 커스텀 프로바이더 선언 방식으로 구체적으로는 Class Provider라고 불리는 형태다.
NestJS의 module.ts파일에서 providers: [LogsRepository] 라고만 적는 것은 사실 providers: [{ provide: LogsRepository, useClass: LogsRepository }]를 축약한 형태다.
provide는 DI 컨테이너에서 인스턴스를 찾기 위한 Key 역할을 한다. 클래스 생성자에서 @Inject(LogsRepository)나 constructor(private readonly logsRepository: LogsRepository)처럼 타입 힌트를 통해 이 식별자를 요청하면, 시스템은 이 키에 연결된 인스턴스를 찾게 된다.
useClass는 실제 구현체로 위에서 설명한 provide식별자가 호출되었을 때, 실제로 인스턴스화할 클래스를 지정하는 역할을 한다. 처음 예시로 작성한 코드에서는 LogsRepository라는 이름으로 객체를 요청받으면 실제로는 InMemoryLogsRepository클래스를 설계도 삼아 객체를 생성하여 반환하게 된다.
그래서 이걸 왜 씀?
이 방식은 인터페이스나 추상클래스를 실제 구현과 분리할 때 유용하다. 애플리케이션의 다른 서비스들은 LogsRepository라는 추상적인 개념에 의존하고 데이터가 DB에 저장되는지 메모리에 저장되는지 상관하지 않도록 추상화를 유지할 수 있다.
또 테스트 환경에서는 메모리 DB를 사용하는 InMemoryLogsRepository를 주입하고, 실제 운영 환경에서는 DatabaseLogsRepository로 바꾸는 등 유연하게 구현체를 교체할 수 있다는 장점이 있다.
마지막으로 주입받는 쪽의 코드는 전혀 수정하지 않고 providers설정 파일 한 곳만 수정함으로써 전체 로직의 데이터 저장 방식을 변경할 수 있게된다.
// logs.repository.ts (추상 클래스 또는 인터페이스)
export abstract class LogsRepository {
abstract save(log: string): void;
}
// in-memory-logs.repository.ts (실제 구현체)
export class InMemoryLogsRepository implements LogsRepository {
save(log: string) {
console.log(`Memory Storage: ${log}`);
}
}
// app.module.ts
import { Module } from '@nestjs/common';
import { LogsRepository } from './logs.repository';
import { InMemoryLogsRepository } from './in-memory-logs.repository';
@Module({
providers: [
{
provide: LogsRepository, // "LogsRepository를 달라고 하면"
useClass: InMemoryLogsRepository, // "InMemoryLogsRepository를 줘라"
},
],
})
export class AppModule {}
// logs.service.ts (사용부)
import { Injectable } from '@nestjs/common';
import { LogsRepository } from './logs.repository';
@Injectable()
export class LogsService {
// 생성자에서 LogsRepository 타입으로 주입받음
// 실제로는 InMemoryLogsRepository의 인스턴스가 들어옴
constructor(private readonly logsRepository: LogsRepository) {}
logData(data: string) {
this.logsRepository.save(data);
}
}만약 이 프로바이더를 여러 모듈에서 사용하려면 모듈화를 시켜줘야하므로 log.module.ts파일을 만들어 다음과 같이 작성해주어야한다.
// log.module.ts
import { Module } from '@nestjs/common';
import { LogRepository } from './repository/log.repository';
import { InMemoryLogRepository } from './repository/in-memory-log.repository';
@Module({
providers: [{ provide: LogRepository, useClass: InMemoryLogRepository }],
exports: [LogRepository],
})
export class LogModule {}
Join the thread
Leave feedback, ask for clarification, or keep a focused discussion attached to this article.