NestJS에서 환경변수 관리하는 방법 - dotenv VS @nestjs/config

Seung Hyeon ·2023년 11월 7일
0

백엔드

목록 보기
9/19
post-thumbnail

Intro

일반적으로 서비스를 개발할 때,

  1. 개발자 PC환경에서 개발과 (단위)테스트를 하고,
  2. 개발한 코드를 스테이지 서버라고 부르는 테스트 환경에 배포하여 통합 테스를 진행한다.
  3. 이후 테스트 서버 환경에서 문제가 없다면 다시 프로덕션 서버로 배포하는 과정으로 거친다.

이렇게 실행환경이 달라지면, 실행환경에 따라 달라지는 환경 변수들이 존재한다.

(예시)

로컬 환경: localhost
스테이지 환경: stage-ver.com
프로덕션 환경: product-ver.com

따라서 실행 환경에 따라 서버에 설정되는 환경변수 파일을 분리 및 관리하는 것이 좋다

두가지 방법이 있다: dotenv 라이브러리 사용, nestjs/config 모듈 사용

dotenv를 이용한 Config 설정


위에서 언급했듯이, 환경변수 파일을 실행환경에 따라 다르게 구성해야하므로

.development.env

DATABASE_HOST=local

.stage.env

DATABASE_HOST=stage-ver.com

.production.env

DATABASE_HOST=product-ver.com

.env파일을 NODE_ENV에 따라 읽도록 하기

※ NODE_ENV에 대한 내용과 생성 방법은 아래에 자세히..

main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as dotenv from 'dotenv'
import * as path from 'path'

dotenv.config({
	path: path.resolve(
		process.env.NODE_ENV === 'production') ? '.production.env'
      : (process.env.NODE_ENV === 'stage') ? '.stage.env' : '.development.env'
  )
});

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

dotenv의 환경을 설정한다. .env파일의 경로를 NODE_ENV의 값에 따라 다르게 지정한다.

아래처럼 예시로 환경변수 DATABASE_HOST의 값을 출력하는 코드를 작성한 후 확인해본다

app.controller.ts

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return process.env.DATABASE_HOST;
  }
}

(추천) Nest의 Config를 활용한 동적 ConfigModule 생성


패키지 설치

설치 : yarn add @nestjs/config

env파일 생성

.dev.env이름의 development 환경 변수 파일을 생성했다. (위치: src > configs > env)

※ 주의할 점: 앞으로 env파일에는 민감한 정보가 들어갈 것이기 때문에 .gitignore파일에 env를 추가하여 깃허브에 푸쉬되지 않도록 해야한다.

.gitignore

**/*.env

package.json수정

Node.js는 NODE_ENV라는 환경 변수를 활용하여 서버의 환경을 구분한다.

매번 터미널을 새로 열때마다 NODE_ENV를 새로 설정하는 것은 귀찮은 일이니, package.json파일을 수정하여 yarn start:dev 명령이 수행될 때 NODE_ENV가 dev(개발)로 설정되도록 했다.

package.json

"scripts": {
    ....
    "start:dev": "cross-env NODE_ENV=dev nest start --watch", // cross-env를 명시
  },

cross-env 모듈을 사용해야하는 이유

단순히 “NODE_ENV=dev nest start --watch”로만 설정할 경우, Mac OS와 Linux에서는 돌아가지만 Window OS에서는 인식이 안된다는 문제점이 있다.

cross-env모듈은 프로젝트 참여자 각각이 MacOS, Windows, Linux 등 다양한 OS 마다 환경변수를 설정하는 방법이 다르기 때문에 이것에 대한 대책을 마련한 모듈이다.

cross-env모듈을 사용하면 OS간의 호환성 문제를 해결할 수 있다.

  • 설치 : yarn add cross-env

참고 : https://inpa.tistory.com/entry/NODE-📚-cross-env-모듈-사용법

이제 .env파일을 NODE_ENV에 따라 읽을 수 있다.

ConfigModule 등록

app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    ConfigModule.forRoot({
      envFilePath: `src/configs/env/.${process.env.NODE_ENV}.env`,  💚
      isGlobal: true,  💛  // 전체적으로 사용하기 위해
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

💚 envFilePath에는 env파일이 위치한 경로를 적어준다

💛 전역 모듈로 동작하게 하여 어느 모듈에서나 사용할 수 있게 해준다.

nest-cli.json 수정

Typescript 코드가 Node.js에서 작동하기 위해 Javascript코드로 컴파일되는 과정이 필요하다.

Typescript가 Javascript로 바뀌어서 dist라는 폴더로 들어가서 실행된다. (dist 폴더는 실제 배포 단계에서 사용된다.)

이때 .env파일은 자동으로 dist폴더로 복사되지 않는다. 따라서 .env파일을 out디렉토리(dist 디렉토리)에 복사할 수 있도록 nest-cli.json에서 옵션을 수정해야한다.

nest-cli.json

{
  ....
  "compilerOptions": {
    "assets": [
      {
        "include": "./configs/env/*.env",
        "outDir": "./dist"
      }
    ]
  }
}

연결 확인 방법

app.service.ts를 약간 수정해서 yarn start:dev로 한번 확인해보자

app.service.ts

@Injectable()
export class AppService {
  getHello(): string {
    return `Hello World! ${process.env.NAME}`;
  }
}

.dev.env

NAME = Seunghyeon

마치며

Nest는 dotenv를 내부적으로 쉽게 활용할 수 있는 @nest/config 패키지를 제공하기 때문에 @nest/config 활용을 추천한다.

 

참고 도서 : NestJS로 배우는 백엔드 프로그래밍

profile
안되어도 될 때까지

2개의 댓글