NestJS 12 마이그레이션 전략: require(esm) 도입과 Standard Schema 기반 검증

Maru

@maru

NestJS 12 마이그레이션 전략: require(esm) 도입과 Standard Schema 기반 검증 패턴의 변화

NestJS 12 마이그레이션 전략: require(esm) 도입과 Standard Schema 기반 검증 패턴의 변화

Node.js 생태계의 대표적인 엔터프라이즈 프레임워크인 NestJS가 12 버전 출시를 앞두고 대대적인 현대화를 준비하고 있습니다. 이번 메이저 업데이트는 기존의 무겁고 느리다는 이미지를 벗어던지기 위해 빌드 속도 향상, 테스트 도구 고도화, 그리고 검증 패러다임 전환에 초점을 맞추었습니다. 대규모 코드베이스를 운영하는 팀이 다가올 업데이트를 어떻게 영리하게 맞이해야 하는지 구체적인 마이그레이션 전략을 공유합니다.

require(esm) 지원으로 하위 호환성을 지키는 ESM 전환

NestJS 12는 모든 공식 패키지를 ESM 전용으로 완전히 전환하며, 실행 환경으로 Node.js 20 이상을 요구합니다. 과거 많은 오픈소스 라이브러리가 ESM으로 마이그레이션할 때 의존성 호환성이 끊겨 대규모 코드베이스를 강제로 재작성해야 했던 고통을 고려하면, 엔터프라이즈 환경에서 이러한 메이저 업데이트는 부담스럽게 다가올 수 있습니다.

하지만 NestJS 12는 Node.js의 네이티브 require(esm) 기능을 수용하여 하위 호환성 마찰을 극적으로 줄였습니다. 덕분에 기존 CommonJS 프로젝트에서도 빌드 설정을 무리하게 변경하지 않고 ESM 기반의 NestJS 12 패키지를 안정적으로 불러와 사용할 수 있습니다. 개발팀이 서비스 안정성을 확보하면서 원하는 타이밍에 맞춰 점진적으로 마이그레이션을 진행할 수 있는 최적의 경로를 마련한 셈입니다.

새로운 프로젝트를 시작할 때의 개발자 경험도 챙겼습니다. @nestjs/cli@next 도구를 통해 신규 프로젝트를 생성하면 CommonJS와 ESM 중 개발환경에 맞는 빌드 방식을 유연하게 선택하여 시작할 수 있습니다.

class-validator를 대체하는 Standard Schema 1.0 네이티브 통합

NestJS 12는 다양한 스키마 검증 라이브러리의 통합 표준인 Standard Schema 1.0 규격을 네이티브로 지원합니다. 기존에는 입력값 유효성 검사를 위해 무겁고 장황한 class-validator 데코레이터 진영에 의존해야 했지만, 이제는 Zod나 Valibot 같은 현대적인 라이브러리를 아무런 래퍼 없이 유연하게 조합할 수 있습니다.

핵심은 새롭게 추가된 StandardSchemaValidationPipe입니다. @Body, @Query, @Param과 같은 기본 데코레이터에 스키마 객체를 직접 전달하면, 프레임워크가 런타임에 유효성을 자동으로 검증하고 컴파일 시점에는 강력한 타입 추론을 제공합니다.

다음은 Zod를 활용해 요청 바디를 간결하게 검증하는 예시입니다.

typescript
import { Controller, Post, Body } from '@nestjs/common';
import { z } from 'zod';

const CreateUserSchema = z.object({
  name: z.string().min(2),
  email: z.string().email(),
});

type CreateUserDto = z.infer<typeof CreateUserSchema>;

@Controller('users')
export class UserController {
  @Post()
  create(
    @Body({ schema: CreateUserSchema })
    data: CreateUserDto,
  ) {
    return data;
  }
}

이 패턴은 클래스를 이중으로 선언하거나 데코레이터를 중복해서 붙이던 보일러플레이트를 대폭 줄여줍니다. 또한 빌드 시점에 스키마와 타입 정의를 단일 소스로 관리할 수 있어 코드의 신뢰성과 개발자 경험을 동시에 개선합니다.

Vitest와 Rspack이 이끄는 모던 툴체인으로의 대대적 교체

대규모 엔터프라이즈 프로젝트에서 NestJS의 고질적인 병목은 느린 컴파일 속도와 무거운 테스트 실행이었습니다. NestJS 12는 오랫동안 기본으로 유지해 온 Webpack, Jest, ESLint 조합의 빌드 툴체인을 Rspack, Vitest, oxlint로 과감히 교체하며 이 문제를 해결합니다.

새 프로젝트를 생성하면 번들러는 Rust 기반의 초고속 빌드 도구인 Rspack으로, 테스트 러너는 대규모 코드베이스에서 더 가볍고 빠른 Vitest로 설정됩니다. 여기에 초고속 린터인 OXC 기반의 oxlint가 기본 린터로 적용되면서, 개발자는 코드 수정 후 빌드와 테스트 결과를 대기 시간 없이 실시간으로 확인할 수 있습니다.

기존 툴체인을 무리하게 즉시 전환할 필요는 없지만, 새로운 빌드 환경을 구축하거나 점진적으로 전환하고자 한다면 성능 이점을 뚜렷하게 느낄 수 있습니다. 새로워진 모던 툴체인을 직접 경험해 보려면 다음 명령어로 프로젝트 구성을 시작할 수 있습니다.

bash
npx @nestjs/cli@next new my-app

Hono, Elysia의 빠른 성장 속에서 NestJS 12가 취한 현실적 타협점

최근 엄청난 처리 속도와 가벼운 콜드 스타트를 주 무기로 내세운 Hono나 Elysia 같은 웹 표준 지향 프레임워크가 급부상하고 있습니다. NestJS 12는 아키텍처 자체가 엔터프라이즈 규모에 최적화되어 있으므로 물리적인 구동 크기가 이들처럼 작을 수는 없습니다. 그러나 네이티브 스키마 지원과 고성능 툴체인 교체는 가볍고 빠른 최신 스택의 개발 경험을 수용하면서도 탄탄한 의존성 주입 생태계를 계속해서 지켜갈 수 있는 영리한 균형점입니다.

성공적인 NestJS 12 마이그레이션을 위한 세 가지 체크포인트

안정적인 전환을 위해 개발팀은 세 가지를 먼저 점검해야 합니다. 첫째, 실행 환경을 Node.js 20 이상으로 서둘러 업그레이드해야 합니다. 둘째, 기존에 널리 활용되던 class-validator 검증 로직을 신규 Standard Schema 규격으로 이관하기 위한 정책을 정의해야 합니다. 마지막으로, 공식 릴리스 전에 @nestjs/cli@next 명령어를 통해 변경된 툴체인과의 호환성을 로컬 환경에서 먼저 테스트해 볼 것을 권장합니다.