왜 SWC인가?
NestJS의 기본 TypeScript 컴파일러는 tsc다. 프로젝트가 커지면 빌드 시간이 30초, 1분을 넘기기 시작한다. SWC(Speedy Web Compiler)는 Rust로 작성된 TypeScript/JavaScript 컴파일러로, tsc 대비 약 20배 빠른 빌드 속도를 제공한다. NestJS 10부터 공식 SWC 지원이 추가되었다.
핵심 차이는 이렇다: tsc는 타입 체크 + 트랜스파일을 동시에 수행하지만, SWC는 트랜스파일만 수행한다. 타입 체크는 IDE나 CI의 별도 단계에서 처리하고, 빌드는 SWC로 최대한 빠르게 수행하는 전략이다.
SWC 적용: 설정 방법
Step 1: 의존성 설치
# SWC 코어 + NestJS CLI 플러그인
npm install -D @swc/core @swc/cli @swc/helpers
# NestJS CLI가 SWC를 인식하도록 설정
# nest-cli.json 수정
Step 2: nest-cli.json 설정
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"builder": "swc",
"typeCheck": true,
"assets": [
{
"include": "**/*.graphql",
"watchAssets": true
}
]
}
}
"builder": "swc" 한 줄이 핵심이다. "typeCheck": true를 설정하면 SWC 빌드와 동시에 별도 프로세스로 tsc 타입 체크를 병렬 실행한다. 빌드는 SWC 속도로 즉시 완료되고, 타입 에러는 비동기로 보고된다.
빌드 속도 비교
| 프로젝트 규모 | tsc | SWC | 개선율 |
|---|---|---|---|
| 소규모 (50 파일) | 3.2s | 0.3s | 10.7x |
| 중규모 (200 파일) | 12.5s | 0.6s | 20.8x |
| 대규모 (500+ 파일) | 35.0s | 1.4s | 25.0x |
| HMR (단일 파일) | 1.5s | 0.05s | 30.0x |
.swcrc 커스텀 설정
// .swcrc — 프로젝트 루트에 생성
{
"$schema": "https://swc.rs/schema.json",
"sourceMaps": true,
"jsc": {
"parser": {
"syntax": "typescript",
"decorators": true, // NestJS 데코레이터 필수
"dynamicImport": true
},
"transform": {
"legacyDecorator": true, // experimentalDecorators 호환
"decoratorMetadata": true, // emitDecoratorMetadata 호환 (DI 필수!)
"decoratorVersion": "2022-03"
},
"target": "es2022",
"keepClassNames": true, // NestJS DI가 클래스명 의존
"baseUrl": ".",
"paths": {
"@app/*": ["src/*"],
"@modules/*": ["src/modules/*"],
"@common/*": ["src/common/*"]
}
},
"module": {
"type": "commonjs" // NestJS는 CJS 사용
},
"minify": false // 서버 코드는 minify 불필요
}
핵심 설정 해설
decoratorMetadata: true는 반드시 활성화해야 한다. NestJS의 의존성 주입은 TypeScript의 emitDecoratorMetadata에 의존하기 때문이다. 이 옵션이 없으면 @Injectable() 클래스의 생성자 매개변수 타입을 알 수 없어 DI가 실패한다.
keepClassNames: true도 중요하다. NestJS는 에러 메시지, 로깅, 프로바이더 토큰에서 클래스 이름을 사용한다. 이 옵션이 없으면 클래스 이름이 맹글링되어 디버깅이 어려워진다.
Path Alias 설정: tsconfig paths 연동
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@app/*": ["src/*"],
"@modules/*": ["src/modules/*"],
"@common/*": ["src/common/*"],
"@config/*": ["src/config/*"]
}
}
}
// SWC는 paths를 트랜스파일 시 해석하지 않음
// 런타임 해석을 위해 tsconfig-paths 사용
// main.ts 또는 package.json scripts에서:
// "start:dev": "nest start --watch"
// nest CLI가 SWC 빌드 시 자동으로 path 매핑 처리
개발 환경: HMR(Hot Module Replacement)
// main.ts — HMR 활성화
declare const module: any;
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
if (module.hot) {
module.hot.accept();
module.hot.dispose(() => app.close());
}
}
bootstrap();
// nest-cli.json — HMR + SWC 조합
{
"compilerOptions": {
"builder": "swc",
"typeCheck": true
},
"watchOptions": {
// 특정 디렉토리 감시 제외 (성능 향상)
"ignored": [
"node_modules",
"dist",
"test",
".git"
]
}
}
// 실행
// nest start --watch --builder swc
// → 파일 변경 시 50ms 이내 리빌드
CI/CD 파이프라인 최적화
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
# 1단계: 타입 체크 (tsc)
- name: Type Check
run: npx tsc --noEmit
# 타입 에러만 검사, 출력 파일 생성 안 함
# 2단계: 빌드 (SWC) — 타입 체크와 병렬 가능
- name: Build
run: nest build
# SWC로 빌드 → 1-2초 완료
# 3단계: 테스트
- name: Test
run: npm run test
# 4단계: E2E 테스트
- name: E2E Test
run: npm run test:e2e
Jest + SWC: 테스트 속도 최적화
테스트도 SWC로 트랜스파일하면 체감 속도가 크게 향상된다.
# @swc/jest 설치
npm install -D @swc/jest
// jest.config.ts
import type { Config } from 'jest';
const config: Config = {
moduleFileExtensions: ['js', 'json', 'ts'],
rootDir: '.',
testRegex: '.*\.spec\.ts$',
// ts-jest 대신 @swc/jest 사용
transform: {
'^.+\.ts$': [
'@swc/jest',
{
jsc: {
parser: {
syntax: 'typescript',
decorators: true,
},
transform: {
legacyDecorator: true,
decoratorMetadata: true,
},
target: 'es2022',
keepClassNames: true,
},
},
],
},
moduleNameMapper: {
'^@app/(.*)$': '/src/$1',
'^@modules/(.*)$': '/src/modules/$1',
'^@common/(.*)$': '/src/common/$1',
},
collectCoverageFrom: ['src/**/*.ts', '!src/**/*.spec.ts'],
coverageDirectory: './coverage',
testEnvironment: 'node',
};
테스트 속도 비교
| 트랜스포머 | 100개 테스트 | 500개 테스트 |
|---|---|---|
| ts-jest | 18s | 85s |
| @swc/jest | 5s | 22s |
Docker 빌드 최적화
# Dockerfile — SWC 멀티스테이지 빌드
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && cp -R node_modules /prod_modules
RUN npm ci
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# SWC 빌드 — 대규모 프로젝트도 2초 이내
RUN npx nest build
# tsc 빌드였다면 여기서 30초+ 소요
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=deps /prod_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY package*.json ./
EXPOSE 3000
CMD ["node", "dist/main.js"]
트러블슈팅: 자주 만나는 문제
1. DI 실패: “Nest can’t resolve dependencies”
// 원인: decoratorMetadata가 비활성화됨
// 해결: .swcrc에서 확인
{
"jsc": {
"transform": {
"decoratorMetadata": true // ← 반드시 true
}
}
}
// 또는 nest-cli.json에서 SWC 빌더 사용 시
// NestJS CLI가 자동으로 메타데이터 설정을 주입함
2. Path Alias 해석 실패
// 증상: Cannot find module '@app/common/utils'
// 원인: SWC는 paths를 빌드 시 해석하지 않음
// 해결 1: nest CLI 사용 (자동 처리)
nest build // ✅ paths 자동 해석
// 해결 2: swc 직접 사용 시 tsconfig-paths 필요
npm install -D tsconfig-paths
// package.json
{
"scripts": {
"start:prod": "node -r tsconfig-paths/register dist/main.js"
}
}
3. Circular Dependency 감지 안 됨
// SWC는 타입 체크를 안 하므로 순환 참조를 감지 못함
// 해결: forwardRef() 사용 + CI에서 tsc --noEmit 실행
// 순환 참조 방지 패턴
@Module({
imports: [forwardRef(() => UserModule)], // 명시적 forwardRef
})
export class OrderModule {}
// CI에서 반드시 타입 체크 단계 추가
// npx tsc --noEmit → 순환 참조 등 타입 에러 잡기
4. GraphQL Code-First 스키마 생성
// GraphQL의 @ObjectType(), @Field() 데코레이터는
// 메타데이터에 의존하므로 추가 설정 필요
// nest-cli.json
{
"compilerOptions": {
"builder": "swc",
"plugins": ["@nestjs/graphql"] // GraphQL 플러그인 추가
}
}
SWC vs esbuild vs tsc 비교
| 항목 | tsc | SWC | esbuild |
|---|---|---|---|
| 언어 | TypeScript | Rust | Go |
| 타입 체크 | ✅ | ❌ | ❌ |
| 데코레이터 메타데이터 | ✅ | ✅ | ❌ |
| NestJS 공식 지원 | ✅ | ✅ | ❌ |
| NestJS 호환성 | 완벽 | 완벽 | ⚠️ DI 불가 |
esbuild는 데코레이터 메타데이터를 지원하지 않아 NestJS에서 사용할 수 없다. SWC가 NestJS 프로젝트의 유일한 대안 고속 빌더다.
SWC는 NestJS 개발 생산성의 가장 효과적인 투자다. nest-cli.json에 "builder": "swc" 한 줄 추가하면 빌드 20배, HMR 30배, 테스트 4배 빨라진다. 대규모 모노레포에서는 분 단위 빌드가 초 단위로 줄어드는 체감 효과를 경험할 수 있다.