메인 콘텐츠로 건너뛰기
pnpm migrate 명령어는 데이터베이스 스키마 변경을 안전하게 관리합니다. Entity 정의를 기반으로 자동으로 마이그레이션을 생성하고, 여러 데이터베이스에 일관되게 적용할 수 있습니다.

기본 개념

마이그레이션은 데이터베이스 스키마 변경을 버전 관리하는 시스템입니다:
  • Entity 기반: Entity 정의에서 자동으로 마이그레이션 생성
  • 순차 실행: 생성 순서대로 마이그레이션 적용
  • 롤백 지원: 실수를 되돌릴 수 있음
  • 다중 DB 지원: 여러 데이터베이스를 동시에 관리

명령어

status - 상태 확인

현재 마이그레이션 상태를 확인합니다.
pnpm migrate status
출력 예시:
Development Master: ✓ Up to date (v20240115_143022)
Testing: ⚠ 2 pending migrations
Production: ✓ Up to date (v20240115_143022)

Prepared migrations:
  • 20240116_101530_add_user_profile
  • 20240116_102045_create_posts_table
상태 종류:
  • ✓ Up to date: 모든 마이그레이션 적용 완료
  • ⚠ N pending: N개의 미적용 마이그레이션
  • ❌ Error: 데이터베이스 연결 실패

run - 마이그레이션 실행

대기 중인 마이그레이션을 모두 적용합니다.
pnpm migrate run
실행 과정:
Running migrations...

Development Master:
  ✓ 20240116_101530_add_user_profile (0.2s)
  ✓ 20240116_102045_create_posts_table (0.3s)

Testing:
  ✓ 20240116_101530_add_user_profile (0.2s)
  ✓ 20240116_102045_create_posts_table (0.3s)

All migrations completed successfully!
자동 생성 및 적용:
  • Entity 변경사항을 감지
  • 마이그레이션 코드 자동 생성
  • 모든 대상 DB에 순차 적용
Sonamu는 Entity 정의를 분석하여 필요한 마이그레이션을 자동으로 생성합니다. 수동으로 마이그레이션 파일을 작성할 필요가 없습니다.

rollback - 롤백

마지막 배치의 마이그레이션을 되돌립니다.
pnpm migrate rollback
실행 과정:
Rolling back last batch...

Development Master:
  ✓ Rollback 20240116_102045_create_posts_table
  ✓ Rollback 20240116_101530_add_user_profile

Rollback completed successfully!
롤백은 데이터 손실을 초래할 수 있습니다. 프로덕션에서는 매우 신중하게 사용하세요.

reset - 전체 초기화

모든 마이그레이션을 롤백합니다.
pnpm migrate reset
주의사항:
  • 모든 테이블이 삭제됩니다
  • 데이터가 모두 손실됩니다
  • 개발 환경에서만 사용하세요

clear - 마이그레이션 기록 삭제

마이그레이션 기록만 삭제합니다 (테이블은 유지).
pnpm migrate clear
사용 시나리오:
  • 마이그레이션 기록이 손상된 경우
  • 수동으로 스키마를 수정한 경우
  • 마이그레이션을 재정렬해야 하는 경우

마이그레이션 생성

자동 생성

Entity를 수정하면 Sonamu가 자동으로 마이그레이션을 생성합니다.
user.entity.ts
// Entity 정의 변경
const UserEntity = {
  properties: [
    {
      name: "email",
      type: "string",
      length: 255,
    },
    // 새 필드 추가
    {
      name: "phone",
      type: "string",
      length: 20,
      nullable: true,
    },
  ],
};
# 상태 확인
pnpm migrate status

# 출력:
# Prepared migrations:
#   • 20240116_103045_add_phone_to_users

# 적용
pnpm migrate run

마이그레이션 파일

생성된 마이그레이션 파일은 src/migrations/ 디렉토리에 저장됩니다.
src/migrations/20240116_103045_add_phone_to_users.ts
import type { Knex } from "knex";

export async function up(knex: Knex): Promise<void> {
  await knex.schema.alterTable("users", (table) => {
    table.string("phone", 20).nullable();
  });
}

export async function down(knex: Knex): Promise<void> {
  await knex.schema.alterTable("users", (table) => {
    table.dropColumn("phone");
  });
}
구조:
  • up(): 마이그레이션 적용 (테이블 생성, 컬럼 추가 등)
  • down(): 마이그레이션 롤백 (변경사항 되돌리기)

지원하는 변경사항

Sonamu가 자동으로 감지하고 마이그레이션을 생성하는 변경사항:
변경 타입설명예시
테이블 생성새 Entity 추가PostEntity 생성
컬럼 추가새 프로퍼티 추가phone 필드 추가
컬럼 수정타입/길이 변경varchar(100)varchar(255)
컬럼 삭제프로퍼티 제거deprecated_field 삭제
인덱스 추가인덱스 정의@index 데코레이터
외래키 추가관계 정의@belongsTo 관계

다중 데이터베이스 관리

Sonamu는 여러 데이터베이스를 동시에 관리할 수 있습니다.

데이터베이스 구성

sonamu.config.ts
export default {
  database: {
    // 개발 환경 - 마스터
    development_master: {
      client: "pg",
      connection: {
        host: "localhost",
        database: "myapp_dev",
        user: "postgres",
        password: "password",
      },
    },
    // 개발 환경 - 슬레이브 (읽기 전용)
    development_slave: {
      // 슬레이브는 자동으로 무시됨
    },
    // 테스트 환경
    test: {
      client: "pg",
      connection: {
        host: "localhost",
        database: "myapp_test",
        user: "postgres",
        password: "password",
      },
    },
    // 프로덕션 환경
    production: {
      client: "pg",
      connection: {
        host: "prod-db.example.com",
        database: "myapp_prod",
        user: "postgres",
        password: process.env.DB_PASSWORD,
      },
    },
  },
};
마이그레이션 대상:
  • _master로 끝나는 데이터베이스
  • _slave가 아닌 모든 데이터베이스

일괄 적용

# 모든 데이터베이스에 적용
pnpm migrate run

# 출력:
# Development Master: ✓ 2 migrations applied
# Testing: ✓ 2 migrations applied
# Production: ✓ 2 migrations applied

실전 워크플로우

1. Entity 변경

user.entity.ts
const UserEntity = {
  properties: [
    // 기존 필드...
    {
      name: "profile_image",
      type: "string",
      nullable: true,
    },
  ],
};

2. 상태 확인

pnpm migrate status
Prepared migrations:
  • 20240116_110230_add_profile_image_to_users

3. 마이그레이션 적용

pnpm migrate run
✓ All migrations applied successfully!

4. 코드 업데이트

user.model.ts
class UserModelClass extends BaseModel {
  async updateProfileImage(userId: number, imageUrl: string) {
    await this.getPuri("w")
      .update({ profile_image: imageUrl })
      .where("id", userId);
  }
}

문제 해결

마이그레이션 충돌

문제: 여러 개발자가 동시에 마이그레이션 생성
Error: Migration conflict detected
해결:
# 1. 최신 코드 가져오기
git pull

# 2. 마이그레이션 상태 확인
pnpm migrate status

# 3. 필요 시 마이그레이션 재생성
pnpm migrate run

데이터베이스 연결 실패

문제: DB 연결 실패
Error: connect ECONNREFUSED 127.0.0.1:5432
해결:
# 1. PostgreSQL 실행 확인
psql -U postgres -l

# 2. 연결 정보 확인
cat sonamu.config.ts

# 3. 데이터베이스 생성
createdb myapp_dev

마이그레이션 순서 오류

문제: 잘못된 순서로 적용됨
Error: Foreign key constraint violation
해결:
# 1. 롤백
pnpm migrate rollback

# 2. 마이그레이션 파일명 수정 (타임스탬프)
mv 20240116_110230_*.ts 20240116_110231_*.ts

# 3. 재적용
pnpm migrate run

베스트 프랙티스

1. 자주 적용하기

# 작은 단위로 자주 마이그레이션
pnpm migrate run  # 매일

2. 프로덕션 전 테스트

# 테스트 DB에서 먼저 확인
pnpm migrate status
pnpm migrate run

# 문제없으면 프로덕션 적용

3. 백업 필수

# 프로덕션 마이그레이션 전 백업
pg_dump myapp_prod > backup_$(date +%Y%m%d).sql

# 마이그레이션 적용
pnpm migrate run

4. 롤백 가능성 고려

// ✅ 롤백 가능
export async function up(knex: Knex) {
  await knex.schema.alterTable("users", (table) => {
    table.string("phone").nullable();
  });
}

export async function down(knex: Knex) {
  await knex.schema.alterTable("users", (table) => {
    table.dropColumn("phone");
  });
}

다음 단계