GitHub Actions로 운영 DB 마이그레이션 자동화하기

개발용과 운영용 데이터베이스를 나눈 뒤에는 검토한 마이그레이션 파일을 운영 DB에도 적용해야 해요. Drizzle과 GitHub Actions를 예로 들어 secret 등록부터 main push 후 자동 실행까지 설명합니다.

핵심 요약

바이브코딩으로 만든 서비스를 공개한 뒤에도 개발용과 운영용 데이터베이스를 하나로 사용하면 안 됩니다.

내 컴퓨터 → 개발 DB → 가짜 사용자와 테스트 주문
실제 서비스 → 운영 DB → 실제 사용자와 실제 주문

개발 DB에서는 기능을 만들며 데이터를 자유롭게 넣고 지울 수 있어야 합니다. 그 작업이 실제 고객 데이터에 영향을 주면 안 되기 때문에 두 DB를 나눠요.

그런데 DB를 나누면 새 문제가 생깁니다. 개발 DB에 추가한 테이블과 컬럼을 운영 DB에도 똑같이 만들어야 해요.

이때 개발 DB 전체를 운영 DB로 복사하지 않습니다. 테이블 구조를 어떻게 바꿀지 적은 마이그레이션 파일만 운영 DB에 적용합니다.

스키마 수정
→ 마이그레이션 파일 생성
→ 개발 DB에서 확인
→ main에 push
→ GitHub Actions가 운영 DB에 적용

개발·운영 DB를 나누는 이유부터 알고 싶다면 개발용과 운영용 데이터베이스를 나눠야 하는 이유를 먼저 읽어보세요. 마이그레이션이라는 말이 낯설다면 스키마와 마이그레이션 설명을 참고하면 됩니다.

왜 GitHub Actions로 실행할까요?

운영 DB를 바꿀 때마다 Supabase Dashboard를 열어 SQL을 직접 복사할 수도 있습니다. 하지만 파일 하나를 빠뜨리거나 순서를 잘못 실행하기 쉬워요. 어느 변경까지 적용했는지도 기억에 의존하게 됩니다.

GitHub Actions를 사용하면 운영 DB를 바꾸는 순서를 하나로 정할 수 있습니다.

GitHub에 기록된 마이그레이션 파일
→ 아직 운영 DB에 적용하지 않은 파일 확인
→ 순서대로 실행
→ 성공 또는 실패 기록을 Actions에 남김

Drizzle의 migrate 명령도 마이그레이션 폴더와 DB의 적용 기록을 비교해 아직 실행하지 않은 파일만 적용합니다. (Drizzle migrate 공식 문서 (새 탭에서 열림))

1. 생성과 적용 명령을 나눠요

Drizzle을 사용한다면 package.json에 다음 두 명령을 준비합니다.

{
  "scripts": {
    "db:generate": "drizzle-kit generate",
    "db:migrate": "drizzle-kit migrate"
  }
}

역할은 다릅니다.

npm run db:generate
→ schema.ts의 변경으로 SQL 마이그레이션 파일을 만듦

npm run db:migrate
→ 현재 연결된 DB에 아직 실행하지 않은 파일을 적용

운영에서는 DB 구조를 즉석에서 맞추는 db:push를 사용하지 않습니다. 개발 중 생성하고 확인한 마이그레이션 파일을 Git에 기록한 뒤, 운영에서는 db:migrate만 실행하세요.

2. 개발 DB에서 먼저 확인해요

예를 들어 주문에 memo 컬럼을 추가한다고 해볼게요. 스키마 코드를 수정한 뒤 마이그레이션 파일을 만듭니다.

npm run db:generate

다음과 같은 SQL 파일이 생깁니다.

ALTER TABLE "orders" ADD COLUMN "memo" text;

로컬의 DATABASE_URL이 개발 DB를 가리키는지 확인하고 적용합니다.

npm run db:migrate

기존 주문과 새 기능이 모두 정상적으로 작동하는지 확인한 뒤 스키마 코드와 생성된 마이그레이션 파일을 함께 commit합니다. commit과 push가 헷갈린다면 코드가 GitHub를 오가는 과정을 참고하세요.

3. GitHub에 운영 DB 주소를 저장해요

GitHub Actions가 운영 DB에 접속하려면 운영용 DATABASE_URL이 필요합니다. 이 주소에는 비밀번호가 들어갈 수 있으므로 워크플로 파일에 직접 적으면 안 돼요.

GitHub 저장소에서 다음 메뉴로 이동합니다.

Settings
→ Secrets and variables
→ Actions
→ New repository secret

이름에는 DATABASE_URL, 값에는 운영 DB 연결 주소를 입력합니다.

워크플로에서는 이 값을 ${{ secrets.DATABASE_URL }}로 불러옵니다. 실제 주소는 저장소 파일에 남지 않고 작업을 실행할 때만 환경변수로 전달됩니다. (GitHub Actions Secret 공식 문서 (새 탭에서 열림))

Supabase를 사용한다면 Dashboard의 Connect에서 현재 프로젝트의 연결 문자열을 확인하세요. (Supabase의 Drizzle 연결 안내 (새 탭에서 열림))

4. GitHub Actions 파일을 만들어요

저장소에 다음 파일을 만듭니다.

.github/workflows/db-migrate.yml

Drizzle 패키지가 packages/db에 있는 npm 모노리포라면 다음처럼 작성할 수 있어요.

name: DB Migrate

on:
  push:
    branches: [main]
    paths:
      - "packages/db/src/schema.ts"
      - "packages/db/drizzle/**"
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: production-db-migration
  cancel-in-progress: false

jobs:
  migrate:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - run: npm ci

      - name: Run migrations
        working-directory: packages/db
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
        run: npm run db:migrate

이 워크플로는 다음과 같이 작동합니다.

프로젝트가 단일 앱이라면 working-directory를 빼고 루트의 마이그레이션 명령을 실행하면 됩니다. 스키마와 마이그레이션 폴더가 다른 위치에 있다면 paths도 실제 경로에 맞게 바꾸세요.

5. main에 push한 뒤 결과를 확인해요

전체 순서는 다음과 같습니다.

1. 스키마 수정
2. npm run db:generate
3. 개발 DB에서 npm run db:migrate
4. 기존 기능과 새 기능 확인
5. 스키마와 마이그레이션 파일 commit
6. main에 push
7. GitHub Actions 실행 결과 확인
8. 실제 서비스 확인

GitHub 저장소의 Actions 탭에서 DB Migrate 작업을 열면 성공 여부와 실행 기록을 볼 수 있습니다. 실패했다면 운영 DB에서 임의로 SQL을 다시 실행하기 전에 Actions에 나온 첫 오류부터 확인하세요.

한 가지 주의할 점이 있습니다. Vercel 배포와 DB 마이그레이션이 같은 push에서 시작되면 두 작업이 동시에 진행될 수 있어요. 새 컬럼을 추가할 때는 우선 비어 있어도 되는 컬럼으로 추가하고, 새 코드가 배포된 뒤에 필수값으로 바꾸는 식으로 변경을 나누는 편이 안전합니다.

AI에게 설정을 맡기는 프롬프트

프로젝트마다 ORM과 폴더 위치가 다르므로 예제 YAML을 그대로 붙이기보다 AI가 현재 구조를 먼저 확인하게 하세요.

이 프로젝트의 운영 DB 마이그레이션을
GitHub Actions로 자동화해줘.

먼저 프로젝트 파일을 읽고 다음을 확인해줘.

- 사용하는 ORM과 마이그레이션 도구
- 스키마와 마이그레이션 파일 위치
- generate와 migrate 명령
- DATABASE_URL을 읽는 설정 파일

확인한 실제 경로에 맞춰
.github/workflows/db-migrate.yml을 만들어줘.

조건은 다음과 같아.

- main에 DB 관련 변경이 push됐을 때만 실행
- 운영에서는 db:push가 아니라 migrate 명령 사용
- 운영 DATABASE_URL은 secrets.DATABASE_URL로 받기
- 마이그레이션이 동시에 두 개 실행되지 않게 설정
- Actions 화면에서 수동 실행도 가능하게 설정
- 비밀값을 코드나 로그에 출력하지 않기

운영 DB 접속과 실제 마이그레이션 실행은 하지 마.
마지막에 내가 GitHub의
Settings → Secrets and variables → Actions에서
직접 등록할 값과 실행 후 확인할 위치를 알려줘.

정리

개발 DB와 운영 DB는 서로 다른 데이터를 저장합니다. 하지만 테이블과 컬럼 구조는 같은 마이그레이션 파일로 맞춰야 해요.

개발 중에는 db:generate로 파일을 만들고 개발 DB에서 확인합니다. 운영 DB 주소는 GitHub Actions Secret에 저장합니다. 검증한 파일을 main에 올리면 GitHub Actions가 db:migrate를 실행합니다.

이 흐름을 만들면 운영 DB에 매번 직접 접속하지 않아도 되고, 어떤 변경이 언제 적용됐는지도 Git과 Actions 기록으로 확인할 수 있습니다.

#운영#데이터베이스#마이그레이션#GitHub#자동화

인스타그램 @ddukddak.build · 페이스북 뚝딱