Module은 @Module() 데코레이터가 달린 클래스를 말한다.
이 데코레이터는 Nest가 애플리케이션 구조를 효과적으로 구성하고 관리 할 수 있도록 메타데이터를 제공한다.
모든 Nest 애플리케이션은 적어도 하나의 모듈을 가진다.
바로 application graph에서 출발점에 해당하는 루트 모듈이다.
이 그래프는 Nest가 관계와 의존관계를 해결하기 위해 사용하는 내부구조이다.
작은 애플리케이션은 하나의 모듈만 가질 수 있지만, 보통은 그렇지는 않다.
모듈은 구성 요소들을 조직할 때, 굉장히 추천되는 방식이다.
대부분의 애플리케이션에서, 기능들에 따라 밀접에서 관련되어 캡슐화된 멀티 모듈 구조를 가지게 될 것이다.
@Module() 데코레이터는 모듈을 명시한 하나의 싱글 오브젝트를 가진다.
providers | Nest injector에 의해 인스턴스화 되거나, 모듈간에 공유되어야 하는 Provider들 |
controllers | 해당 모듈에서 인스턴스화 되어야 하는 Controller들 |
imports | 이 모듈에서 필요한 Provider를 내보내는 Module들 |
exports | 이 모듈에 있는 Provider 중에 다른 모듈에서도 사용 할 수 있도록 내보내야 하는 Provider들 |
모듈은 기본적으로는 provider들을 캡슐화 한다.
이 말은 현재 모듈에서 사용하는 일부의 provider들을 주입받거나, 다른 모듈에서 명시해서 주입받아야 한다는 말이다.
- Feature modules
우리의 예시에서 CatsController와 CatsService는 매우 밀접한 관계가 있었으며, 같은 애플리케이션 도메인에서 제공되었었다.
그러면 이것들을 기능 모듈에 그룹 지을 수 있을 것 같다.
기능 모듈은 특정한 기능들의 코드를 조직해서 편리하게 영역을 만들어준다.
이것은 SOLID원칙을 준수하며, 팀과 애플리케이션의 성장에 굉장히 중요하다.
cats를 모아서 cats module로 묶어 모듈로 분리해보자.
nest g module cats
이렇게 cats 모듈을 만들고, 이 곳으로 모든 코드들을 다 옮겨준다.
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule {}
이렇게 AppModule에 CatsModule을 넣어준다.
이제 다음과 같은 구조가 될 것이다.
- Shared modules
Nest에서 모듈들은 기본적으로 싱글톤이다.
그렇기에 같은 인스턴스를 멀티 모듈에서 쉽게 공유가 가능하다.
모든 모듈은 기본적으로는 공유 모듈이다.
모듈은 일단 생성되면 어느 모듈에서든 사용이 가능하다.
우리가 CatsService를 다른 모듈간에 공유한다고 상상해보자.
일단 CatsModule에서 해당 CatsService를 export 해야한다.
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
imports: [CatsModule],
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService],
})
export class CatsModule {}
이제 CatsModule을 import한 모듈은 CatsService에 접근이 가능하며 해당 인스턴스를 공유한다는 것도 굉장히 중요한 포인트이다.
만약 직접 CatsService를 가져가서 등록하게 된다면, 물론 이것도 가능은 하다.
하지만 그렇게하면 각각의 모듈이 각각의 인스턴스를 만들며, 같은 서비스가 또 생성되기에 메모리가 낭비되고 만약 해당 서비스에 상태가 존재했다면 이런 상태가 일치하지 않는 상태 불일치 문제가 발생하기도 한다.
이것을 모듈에서 감싸고 export 하는 방법은 CatsModule을 import하는 모든 모듈들에 같은 인스턴스가 공유되는 것을 보장한다.
이것은 메모리의 낭비를 줄이고 같은 상태를 공유하기에 예상치 못한 에러를 줄일 수 있다.
이런 서비스를 효율적으로 애플리케이션 간에 공유하는 것은 모듈화와 DI가 가능한 프레임워크의 핵심적인 기능이다.
- Module re-exporting
모듈은 자신의 내부 provider를 export 할 수 있다.
그리고 추가적으로 자신이 import 했던 모듈을 다시 export 할 수 있다.
아래처럼 CommonModule은 CoreModule에게 import, export 되고 있으며, 이것은 다른 모듈이 이거 하나로 다 import 될 수 있도록 만든다.
@Module({
imports: [CommonModule],
exports: [CommonModule],
})
export class CoreModule {}
- Dependency injection
모듈 클래스는 provider를 주입 받을 수 있다.
@Module({
imports: [CatsModule],
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService],
})
export class CatsModule {
constructor(private catsService: CatsService){}
}
그러나 순환참조 문제 때문에 모듈 자체에서 provider를 주입받을 수는 없다.
- Global modules
만약 어디에서 항상 사용하는 모듈이 있다면, 그것을 모두 추가해주기는 힘들것이다.
Nest에서 전역으로 제공되는 provider를 만들고 싶다면, @Global 데코레이터로 글로벌 모듈로 만드는 것이 좋다.
@Global()
@Module({
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService],
})
export class CatsModule {}
@Global() 데코레이터는 모듈을 전역으로 만든다.
글로벌 모듈은 한 번만 등록하며, 보통 루트 혹은 코어 모듈에서 한다.
- Dynamic modules
Nest에서 다이나믹 모듈은 런타임에 생성되도록 만들어준다.
만약 유연한 설계가 필요한 개발자라면 굉장히 유용한 기능이다.
특정한 옵션에 따라 모듈을 커스텀 할 수 있기 때문이다.
@Module({
providers: [Connection],
exports: [Connection],
})
export class DatabaseModule {
static forRoot(entities = [], options?): DynamicModule {
const providers = createDatabaseProviders(options, entities);
return {
module: DatabaseModule,
providers: providers,
exports: providers,
};
}
}
'Node > Nest 공식문서' 카테고리의 다른 글
Providers (0) | 2025.08.21 |
---|---|
Controllers (0) | 2025.08.20 |
First steps (2) | 2025.08.18 |
Introduction (4) | 2025.08.18 |