DB

[TypeORM] cross-env 환경에서 마이그레이션 하기

bill's tech log 2025. 4. 13. 19:31

 
ORM을 사용하면 SQL 질의어 없이 코드테이블을 정의하고 관리할 수 있다. Node 진영에서 많이 사용하는 TypeORM 또한 이와 마찬가지로 편리한 기능들을 제공한다. 마이그레이션은 데이터베이스 스키마의 변경사항을 버전 관리하고 적용하는 과정으로, 개발 과정에서 데이터베이스 구조가 변경될 때마다 안전하게 업데이트할 수 있게 해준다. 특히 팀 단위 개발이나 여러 환경(개발, 스테이징, 프로덕션)에서 일관된 데이터베이스 구조를 유지하는 데 필수적이다. 오늘은 평소에 TypeORM을 사용할 때 내가 사용하는 마이그레이션 방식에 대해서 정리하고자 한다.

 

마이그레이션 방식 설명에 앞서 TypeORM은 0.3.20 버전을 사용중이고 NestJS는 10.x.x 버전을 기준으로 작성했다. 추가로 cross-env 환경에서 스테이징, 프로덕션으로의 마이그레이션 과정을 다룰 예정이다. 보통 스테이징은 로컬에 컨테이너나 직접 데이터베이스를 설치한 이후 synchronize: true로 관리할 수도 있지만, 현재 회사에서는 별도의 스테이징 DB와 프로덕션 DB를 클라우드에서 분리시켜서 사용하고 있기 때문에, 두가지 케이스에서 마이그레이션을 진행할 때 주의해야 되는 부분도 다룰 예정이다.
 
추가로 ts-node를 기반으로 마이그레이션 하는 방식을 공식문서나 여러 블로그에서 정리해둔 내용들이 많이 있는데, 이번 글에서는 ts-node를 사용한 마이그레이션 방식을 다루지 않을 예정이다. 대신 TypeORM CLI를 활용하여 컴파일된 JavaScript 파일 기반으로 마이그레이션을 진행하는 방법을 설명할 것이다.
 
 

TypeORM CLI 설치 

마이그레이션을 진행하고자 하는 환경에서 TypeORM CLI를 설치한다. 

# 전역 패키지로 TypeORM을 설치
$npm i -g typeorm 

# 설치 확인
$typeorm -v

 

패키지 및 환경설정 세팅 

NestJS 프로젝트 내부 경로에 data-source.ts 파일을 생성한다. data-source.ts 파일을 기점으로 마이그레이션을 관리한다. 필자는 위에서 cross-env 환경에 맞춰서 마이그레이션을 관리한다고 했다. 그렇기 때문에, cross-env 패키지를 설치하고, data-source.ts 파일에서 현재 환경에 맞는 .env 파일을 load하고 그에 맞춰서 마이그레이션을 진행할 것이다.

data-source.ts 파일 생성

 

$pnpm i dotenv
$pnpm i cross-env 
$touch .env.development .env.production

 

위와 같이 cross-env, dotenv 패키지를 설치하고, 각각의 환경에 맞는 .env 파일을 생성 후 환경변수를 기입한다. (환경변수 기입 내용은 각각 스테이징, 프로덕션 환경에 맞춰서 기입해주면 된다.)

 

import { DataSource } from 'typeorm';
import * as dotenv from 'dotenv';

/** staged production 환경에 따른 마이그레이션 파일 셋업 */
if (process.env.NODE_ENV === 'development') {
  console.log('migration development environment');
  dotenv.config({ path: './.env.development' });
} else {
  console.log('migration production environment');
  dotenv.config({ path: './.env.production' });
}

export default new DataSource({
  type: process.env.DB_ENGINE as 'mysql',
  host: process.env.DB_HOST,
  port: Number(process.env.DB_PORT || '3306'),
  username: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  synchronize: false,
  logging: false,
  entities: ['dist/**/*.entity.js'],
  migrations: ['dist/db/migrations/*.js'],
  migrationsTableName: 'migrations',
  migrationsRun: false,
});

 

패키지 설정과 환경변수 세팅이 완료되면 data-source.ts 파일에 위와 같이 작성한다. 
실제 마이그레이션 진행시 cross-env 환경에 맞춰서 .env 파일을 다르게 가져와서 진행한다. 

 
 

Migration 실행 스크립트 작성 

package.json 

"scripts": {
... 생략
	"migration:generated:dev": "NODE_ENV=development typeorm migration:generate ./src/database/migrations/init -d ./dist/database/data-source.js",
	"migration:generated:prod" : "NODE_ENV=production typeorm migration:generate ./src/database/migrations/init -d ./dist/database/data-source.js"
    }

 

typeorm cli를 사용하면 별도로 DDL(Data Definition Language) 없이 Entity의 변경 사항을 캐치해서 migration 파일을 생성해준다. 마이그레이션 시 매번 스크립트를 입력하기 귀찮기 때문에 프로젝트 package.json 파일에 위와 같이 generate 스크립트를 cross-env 환경에 맞춰서 생성되도록 정의한다.

 
 

이후 실제 터미널에 cross-env 환경에 맞는 generated 명령어를 입력한다. 

$pnpm migration:generated:dev # 스테이징용 generated 파일 로드 
$pnpm migration:generated:prod # 프로덕션용 generated 파일 로드

 

generate 명령어가 정상적으로 실행되면, 아래와 같이 migrations 파일이 생성된다. 파일명은 현재 시간의 타임스탬프(UNIX 시간)를 기준으로 생성되며, 이를 통해 마이그레이션이 실행되는 순서를 보장한다.

cli 명령어로 생성된 migrations 파일

 
 
 

최종적으로 generated로 생성된 파일에서 정상적으로 DDL 구문이 작성이 완료되었다면, migration을 각 cross-env 환경에 맞춰서 실행 하기 위해 package.json 파일에 아래와 같이 스크립트를 작성한다. 

"scripts": {
... 생략

	"build:dev": "NODE_ENV=development nest build",
	"build:prod": "NODE_ENV=production nest build",
	"migration:run:dev": "pnpm run build:dev && typeorm migration:run -d ./dist/db/data-source.js",
	"migration:run:prod": "pnpm run build:prod && typeorm migration:run -d ./dist/db/data-source.js"

    }

 

dist 파일에 data-source.ts 파일을 기반으로 마이그레이션이 진행되기 때문에, 스테이징 & 프로덕션 환경에 맞춰서 마이그레이션을 실행하면, 각 환경에 맞춰서 마이그레이션이 정상적으로 이루어진다. (스크립트 내부에 별도의 build 명령어로 dist 폴더 내부에 data-source.js 파일을 생성)

 

 
위와 같은 방식으로 진행하면, 좀 번거롭지만 실제 프로덕션에 변경사항을 배포하기 이전에 스테이징에서 안정적으로 체크를 하고 반영할 수 있고, CI/CD 파이프라인을 구성할 때도 유용하기 때문에 위의 방식을 선호하는 편이다.

 
 
 

'DB' 카테고리의 다른 글

[DB] 뷰(View) 란?  (1) 2024.05.09