NestJS는 TypeScript를 전제로 모듈·의존성 주입(Dependency Injection, DI)·데코레이터(decorator) 구조를 제공하는 Node.js 서버 프레임워크다. 2017년 Kamil Myśliwiec가 만들었고, 구조를 강제하는 방식 때문에 흔히 "Node.js의 Spring"이라 불린다.
배경
- Express·Koa는 훌륭한 HTTP 라이브러리지만 프로젝트 구조에 대해 아무것도 정하지 않는다. 팀마다 구조가 달라 규모가 커지면 유지보수가 어려웠다
- 프론트엔드의 Angular가 모듈·DI·데코레이터로 큰 앱을 조직하는 방식을 보여 줬고, Nest는 이 설계를 서버로 가져왔다
- 데코레이터와 메타데이터 리플렉션(reflection)을 쓰는 구조라 처음부터 TypeScript 1급이다(TypeScript 데코레이터)
주요 특징
- 모듈:
@Module()로 컨트롤러와 프로바이더를 묶고, 필요한 것만 export·import해 도메인 경계를 드러낸다 - DI 컨테이너(DI container): 생성자에 타입만 적으면 인스턴스를 만들어 넣어 준다. 테스트에서 가짜로 바꾸기 쉽다(의존성 주입 (DI))
@Injectable()
export class CatsService {}
@Controller('cats')
export class CatsController {
constructor(private readonly catsService: CatsService) {}
@Get(':id')
findOne(@Param('id') id: string) { /* ... */ }
}- 요청 파이프라인의 표준 자리: Guard(인증·인가), Interceptor(변환·로깅·캐시), Pipe(검증·변환), Exception Filter(예외 처리). 횡단 관심사를 어디에 둘지 고민이 줄어든다. 스프링의 필터체인과 AOP(Aspect-Oriented Programming)가 하는 일과 비슷하다
요청은 Guard → Interceptor(핸들러 전) → Pipe → 핸들러 → Interceptor(핸들러 후) 순서로 지나고, 도중에 던진 예외는 Exception Filter가 받아 응답으로 바꾼다(Request lifecycle).
flowchart TD R[요청] --> G["Guard (인증 · 인가)"] G --> I1["Interceptor 전"] I1 --> P["Pipe (검증 · 변환)"] P --> H[핸들러] H --> I2["Interceptor 후"] I2 --> S[응답] G & P & H -.->|예외| X[Exception Filter]
- 플랫폼 독립: 기본 HTTP 엔진은 Express, 설정으로 Fastify로 바꿀 수 있다
- HTTP 너머: GraphQL, WebSocket, gRPC, Kafka 같은 메시지 기반 마이크로서비스를 같은 모델로 다룬다
- 공식 생태계: ORM 연동, Passport 인증, 스케줄러, Swagger 문서 생성, CLI 보일러플레이트
트레이드오프
구조를 강제하는 만큼 작은 프로젝트에서는 보일러플레이트(boilerplate)가 과하게 느껴진다. 중대형 팀 프로젝트에서 일관성이 필요할 때 빛난다. 스프링과의 대응은 스프링 빈과 IoC 컨테이너과 Spring MVC 요청 흐름를 함께 보면 쉽다.
출처: NestJS 문서: Introduction(Philosophy) · Modules · Providers