개인의 기록
  • 소개
  • 프로젝트
  • 글
  • 링크

© 2026 newgirok

← 글 목록

NestJS Module — 관련 기능을 묶는 기본 단위

2025년 2월 19일
NestJSModule@ModuleFeature ModuleShared Module

NestJS 애플리케이션은 Module 단위로 구성된다. 각 Module은 연관된 Controller, Provider, Service를 하나의 경계 안에 묶어 관심사를 분리한다. 이 경계 덕분에 애플리케이션이 커져도 의존성 방향이 명확하게 유지된다.

@Module 데코레이터

Module은 @Module 데코레이터 하나로 정의된다. 데코레이터에 전달하는 메타데이터 객체가 해당 모듈의 역할을 결정한다.

import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

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

imports — 이 모듈에서 사용할 다른 모듈을 등록한다. controllers — HTTP 요청을 처리하는 Controller 목록. providers — DI 컨테이너에 등록할 Service·Repository 등. exports — 다른 모듈이 주입받을 수 있도록 공개할 Provider 목록.

모듈 종류

종류설명
Root ModuleAppModule. 애플리케이션 진입점, 모든 모듈의 루트
Feature Module도메인별로 분리한 모듈 (UsersModule, OrdersModule 등)
Shared Module여러 Feature Module이 공통으로 사용하는 Provider를 exports로 공개
Global Module@Global 데코레이터로 모든 모듈에 자동 주입
Dynamic ModuleforRoot / forFeature 패턴으로 런타임에 설정을 주입

의존성 그래프

NestJS는 부트스트랩 시점에 모든 @Module 메타데이터를 분석해 의존성 그래프를 구성한다. 그래프가 순환 참조 없이 DAG(Directed Acyclic Graph) 형태여야 정상 부팅된다.

AppModule
├── UsersModule
│   └── exports: [UsersService]
├── OrdersModule
│   └── imports: [UsersModule]   ← UsersService 주입 가능
└── DatabaseModule (Global)
    └── @Global() → 모든 모듈에서 자동 사용 가능

Shared Module 패턴

같은 Provider를 여러 모듈에서 쓰려면 해당 Provider를 보유한 모듈을 Shared Module로 만들고 exports에 올린다. imports 없이 Provider를 직접 복사·붙여넣기하면 인스턴스가 여러 개 생겨 상태 불일치가 발생한다.

// shared/database.module.ts
@Module({
  providers: [DatabaseService],
  exports: [DatabaseService],   // 공개
})
export class DatabaseModule {}

// users/users.module.ts
@Module({
  imports: [DatabaseModule],    // 가져오기
  providers: [UsersService],
})
export class UsersModule {}

NestJS의 Module은 싱글턴 스코프가 기본이다. 같은 모듈을 여러 곳에서 imports해도 Provider 인스턴스는 하나만 생성된다.

Dynamic Module — forRoot / forFeature

설정값을 런타임에 주입해야 할 때 Dynamic Module 패턴을 사용한다. TypeOrmModule.forRoot나 ConfigModule.forRoot가 대표적인 예다.

@Module({})
export class LoggerModule {
  static forRoot(options: LoggerOptions): DynamicModule {
    return {
      module: LoggerModule,
      providers: [
        { provide: LOGGER_OPTIONS, useValue: options },
        LoggerService,
      ],
      exports: [LoggerService],
      global: options.global ?? false,
    };
  }
}

forRoot는 앱 전역 설정에, forFeature는 특정 Feature Module 범위의 설정에 쓴다. 이 패턴 덕분에 라이브러리 수준의 모듈도 사용자 설정을 유연하게 받을 수 있다.

← 이전 글NestJS Application — 애플리케이션 시작점
다음 글 →NestJS Controller — HTTP 요청을 처리하는 클래스