-
Notifications
You must be signed in to change notification settings - Fork 0
nestJS 환경변수 관리
express나 다른 node 개발할 때, 환경변수를 dotenv
로 관리했지만, NestJS에서는 @nestjs/config
모듈을 활용하는 것이 권장된다고 합니다. 이에 따라서 학습하고 정리를 했습니다. 참고로 .env
파일을 사용하는 것은 동일해서 어렵지 않습니다.
2024-11-05 기준 main.ts에 적용되어 있습니다.
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ConfigService } from '@nestjs/config';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// ConfigService 가져오기
const configService = app.get(ConfigService);
// HOST와 PORT 설정
const host = configService.get<string>('HOST') || 'localhost';
const port = configService.get<number>('PORT') || 3000;
await app.listen(port, host);
console.log(`lico is running on: http://${host}:${port}`);
}
bootstrap();
NestJS는 자체적인 환경변수 관리 솔루션인 @nestjs/config
모듈을 제공합니다. 이는 NestJS의 모듈 시스템과 통합되어 더 편리하고 구조적인 환경변수 관리를 가능하게 합니다.
주요 이유:
- 통합성: NestJS의 모듈 시스템과 자연스럽게 통합됩니다.
- 유효성 검사: 환경 변수의 유효성을 검사할 수 있는 기능을 제공합니다.
-
유연성: 다양한 환경별
.env
파일을 손쉽게 관리할 수 있습니다. -
전역 사용:
isGlobal
옵션을 통해 애플리케이션 전체에서ConfigService
를 쉽게 사용할 수 있습니다.
환경별로 .env
파일을 분리하여 관리하고, @nestjs/config
모듈을 설정하는 방법을 설명합니다. 우리의 환경은 dev
와 local
로 구분하였으며, 프로덕션 환경은 클라우드 설정을 통해 관리합니다.
프로젝트 루트 디렉토리에 여러 환경별 .env
파일을 생성합니다.
-
.dev.env
# 서버 설정 PORT=3000 # 데이터베이스 설정 DB_HOST=dev-db.example.com DB_PORT=3306 DB_USERNAME=dev_user DB_PASSWORD=dev_password DB_DATABASE=dev_db # OAuth 설정 GITHUB_CLIENT_ID=your_github_client_id GITHUB_CLIENT_SECRET=your_github_client_secret GOOGLE_CLIENT_ID=your_google_client_id GOOGLE_CLIENT_SECRET=your_google_client_secret NAVER_CLIENT_ID=your_naver_client_id NAVER_CLIENT_SECRET=your_naver_client_secret
-
.local.env
# 서버 설정 PORT=3000 # 데이터베이스 설정 DB_HOST=localhost DB_PORT=3306 DB_USERNAME=local_user DB_PASSWORD=local_password DB_DATABASE=local_db # OAuth 설정 GITHUB_CLIENT_ID=your_github_client_id GITHUB_CLIENT_SECRET=your_github_client_secret GOOGLE_CLIENT_ID=your_google_client_id GOOGLE_CLIENT_SECRET=your_google_client_secret NAVER_CLIENT_ID=your_naver_client_id NAVER_CLIENT_SECRET=your_naver_client_secret
-
.env
(기본 환경, 프로덕션에서는 별도로 관리)# 서버 설정 PORT=3000 # 데이터베이스 설정 DB_HOST=prod-db.example.com DB_PORT=3306 DB_USERNAME=prod_user DB_PASSWORD=prod_password DB_DATABASE=prod_db # OAuth 설정 GITHUB_CLIENT_ID=your_github_client_id GITHUB_CLIENT_SECRET=your_github_client_secret GOOGLE_CLIENT_ID=your_google_client_id GOOGLE_CLIENT_SECRET=your_google_client_secret NAVER_CLIENT_ID=your_naver_client_id NAVER_CLIENT_SECRET=your_naver_client_secret
저희가 개발환경이 여러가지 인데 이걸 동적으로 관리할 수 있을 거 같습니다.
다양한 환경에서 NODE_ENV
를 설정하기 위해 cross-env
모듈을 사용한다고 하는데 cross-env
는 아직 설치하지 않았습니다.
환경 변수를 사용하는 방법에는 여러 가지가 있습니다. 기본적으로 process.env
를 직접 사용하는 방법과 ConfigService
를 사용하는 방법이 있습니다.
NestJS의 ConfigService
를 사용하면, 타입 안전성과 유효성 검사를 활용할 수 있어 더욱 안전하게 환경 변수를 관리할 수 있습니다.
서비스에서 ConfigService
사용 예시:
// users.service.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class UsersService {
constructor(private readonly configService: ConfigService) {}
private readonly gatewayDomain: string = this.configService.get<string>('GATEWAY_DOMAIN', 'localhost');
// 나머지 서비스 로직
}
주요 포인트:
-
ConfigService
를 주입하여 사용. -
get<T>(key: string, defaultValue?: T)
메서드를 통해 환경 변수 값을 가져옴. - 두 번째 인자로 기본값을 설정할 수 있어, 환경 변수가 정의되지 않았을 때 기본값을 사용할 수 있습니다.
필요에 따라 process.env
를 직접 사용할 수도 있습니다. 하지만 이 방법은 타입 안전성이 없고, 환경 변수의 유효성을 보장하기 어려워 권장되지 않습니다.
const port = process.env.PORT || 3000;
ConfigModule
을 전역으로 설정(isGlobal: true
)하면, 애플리케이션의 모든 모듈에서 별도의 설정 없이 ConfigService
를 사용할 수 있습니다. 이는 코드의 중복을 줄이고, 환경 변수 접근을 일관성 있게 유지하는 데 도움이 됩니다.
환경 변수가 올바르게 설정되었는지 확인하는 것은 중요합니다. 잘못된 환경 변수 값은 애플리케이션의 예기치 않은 동작을 초래할 수 있습니다. NestJS에서는 class-validator
와 class-transformer
를 활용하여 환경 변수의 유효성을 검사할 수 있습니다.
env.validation.ts
작성:
// src/util/validate/env.validation.ts
import { plainToClass } from 'class-transformer';
import { IsEnum, IsNumber, IsString, validateSync } from 'class-validator';
enum Environment {
Local = 'local',
Dev = 'dev',
Prod = 'prod',
}
class EnvironmentVariables {
@IsEnum(Environment)
NODE_ENV: Environment;
@IsNumber()
PORT: number;
@IsString()
DB_HOST: string;
@IsNumber()
DB_PORT: number;
@IsString()
DB_USERNAME: string;
@IsString()
DB_PASSWORD: string;
@IsString()
DB_DATABASE: string;
// 추가적인 환경 변수들...
}
export function validate(config: Record<string, unknown>) {
const validatedConfig = plainToClass(EnvironmentVariables, config, { enableImplicitConversion: true });
const errors = validateSync(validatedConfig, { skipMissingProperties: false });
if (errors.length > 0) {
throw new Error(errors.toString());
}
return validatedConfig;
}
app.module.ts
파일을 수정하여 유효성 검사 함수를 ConfigModule
에 통합합니다.
// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module';
import { CategoriesModule } from './categories/categories.module';
import { StreamingModule } from './streaming/streaming.module';
import { VideosModule } from './videos/videos.module';
import { validate } from './util/validate/env.validation';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: `.${process.env.NODE_ENV}.env`,
validate, // 유효성 검사 함수 추가
}),
AuthModule,
UsersModule,
CategoriesModule,
StreamingModule,
VideosModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
주요 포인트:
-
validate
함수를ConfigModule.forRoot
에 추가하여 애플리케이션 시작 시 환경 변수의 유효성을 검사합니다. - 유효성 검사에 실패하면 애플리케이션이 시작되지 않고 에러를 던집니다.