스키마와 마이그레이션이란? 바이브코딩하다 만나는 데이터베이스 용어
데이터베이스 스키마는 테이블·컬럼·관계 같은 현재 구조이고, 마이그레이션은 그 구조를 바꾸는 실행 절차와 기록이에요. 마이그레이션 파일을 만들었다고 실제 DB가 바뀐 것은 아니므로 적용 대상과 기존 데이터 영향을 확인한 뒤 실행해야 해요.
핵심 요약
- 스키마는 테이블·컬럼·자료형·관계로 표현한 데이터베이스의 현재 설계입니다.
- 마이그레이션 파일을 생성하는 일과 실제 데이터베이스에 적용하는 일은 서로 다릅니다.
- 기존 데이터가 있다면 백업하고 단계적으로 변경하며 삭제 같은 파괴적 작업을 먼저 점검합니다.
AI에게 지출 관리 앱에 메모 기능을 추가해달라고 했더니 이런 답이 돌아옵니다.
expenses테이블에memo컬럼을 추가하는 마이그레이션을 만들었습니다. 마이그레이션을 실행해 데이터베이스 스키마에 반영하세요.
앱 화면에 입력칸 하나를 추가해달라고 했을 뿐인데 갑자기 스키마와 마이그레이션이라는 말이 등장했어요. 파일도 만들어졌다는데, 이제 기능이 완성된 것인지 따로 실행해야 하는 것인지 알기 어렵습니다.
두 용어의 관계는 생각보다 단순해요. 스키마는 데이터베이스의 현재 구조이고, 마이그레이션은 그 구조를 바꾸는 과정과 기록입니다.
스키마는 데이터를 담는 설계도예요
지출 관리 앱에는 지출을 저장하는 expenses 테이블이 필요합니다. 처음에는 다음과 같은 구조로 만들 수 있어요.
| 컬럼 | 저장하는 값 | 데이터 형태 |
|---|---|---|
id |
지출을 구분하는 고유 번호 | UUID |
amount |
사용한 금액 | 숫자 |
category |
식비, 교통비 같은 분류 | 문자열 |
spent_at |
돈을 사용한 날짜 | 날짜 |
user_id |
지출을 기록한 사용자 | 사용자 ID |
이처럼 어떤 테이블이 있고, 각 테이블에 어떤 컬럼을 어떤 형태로 저장할지 정한 구조를 스키마(schema)라고 합니다.
스키마에는 테이블과 컬럼 외에도 여러 규칙이 포함될 수 있어요.
- 금액은 반드시 입력해야 합니다.
- 같은 지출은 서로 다른
id를 가져야 합니다. user_id에는 실제로 존재하는 사용자의 ID만 들어갈 수 있습니다.- 사용자가 삭제되었을 때 그 사용자의 지출을 어떻게 처리할지 정합니다.
- 날짜별 지출을 빠르게 찾을 수 있도록 인덱스를 만듭니다.
스키마는 데이터 자체가 아니라 데이터를 담는 모양과 지켜야 할 규칙입니다. 스프레드시트에 비유하면 셀 안에 입력한 지출 내역은 데이터이고, 시트 이름과 열의 구성, 각 열에 입력할 수 있는 값의 규칙은 스키마에 가까워요.
각 컬럼에 문자열, 숫자, 날짜 중 무엇을 담을지 정하는 방법은 데이터 타입이 중요한 이유에서 더 자세히 볼 수 있어요.
참고로 PostgreSQL이나 Supabase 화면에서는 public 스키마라는 표현도 볼 수 있습니다. 이때의 스키마는 여러 테이블을 묶는 이름 공간을 뜻해요. 같은 단어가 조금 더 좁은 의미로 쓰인 경우지만, 입문 단계에서는 우선 “데이터베이스 구조”라는 뜻부터 이해해도 충분합니다.
앱이 바뀌면 스키마도 바뀌어요
처음 정한 구조가 영원히 유지되는 앱은 거의 없습니다. 지출 관리 앱을 사용하다 보면 새로운 요구가 생겨요.
- 지출마다 메모를 남기고 싶습니다.
- 영수증 이미지 주소를 저장하고 싶습니다.
- 카테고리를 문자열이 아니라 별도 테이블로 관리하고 싶습니다.
- 여러 통화를 지원하기 위해 통화 단위를 추가하고 싶습니다.
화면에 메모 입력칸만 추가한다고 메모가 자동으로 데이터베이스에 저장되는 것은 아닙니다. 앱이 memo라는 값을 보내더라도 데이터베이스에 그것을 담을 컬럼이 없다면 저장할 수 없어요.
그래서 기능을 변경할 때는 화면과 코드뿐 아니라 데이터베이스의 스키마도 함께 바꿔야 할 때가 있습니다.
ALTER TABLE expenses
ADD COLUMN memo text;
이 SQL은 expenses 테이블에 문자열을 저장할 수 있는 memo 컬럼을 추가합니다. 실행하고 나면 데이터베이스의 스키마가 이전과 달라집니다.
마이그레이션은 구조를 바꾼 기록이에요
데이터베이스 구조를 바꿀 때마다 대시보드에서 직접 컬럼을 추가할 수도 있습니다. 하지만 무엇을 어떤 순서로 바꾸었는지 기록하지 않으면 곧 문제가 생겨요.
내 컴퓨터에서 사용하는 개발용 데이터베이스에는 memo 컬럼이 있는데 실제 사용자가 접속하는 운영 데이터베이스에는 없을 수 있습니다. 새로 합류한 팀원의 데이터베이스도 서로 다른 구조가 될 수 있어요. 문제가 발생했을 때 어떤 변경이 원인이었는지도 찾기 어렵습니다.
그래서 스키마 변경 명령을 파일로 남기고 순서대로 실행합니다. 이 변경 과정과 파일을 보통 마이그레이션(migration)이라고 불러요.
migrations/
├── 001_create_expenses.sql
├── 002_add_memo_to_expenses.sql
└── 003_create_categories.sql
이 기록을 순서대로 보면 데이터베이스가 어떻게 현재 모습이 되었는지 알 수 있습니다.
지출 테이블 생성
→ 메모 컬럼 추가
→ 카테고리 테이블 생성
집에 비유하면 스키마는 지금 집의 방과 문이 표시된 평면도이고, 마이그레이션은 벽을 세우고 문을 추가하기 위한 공사 지시서예요. 공사 지시서를 순서대로 실행하면 다른 집도 같은 구조로 만들 수 있습니다.
파일을 만들었다고 데이터베이스가 바뀐 것은 아니에요
바이브코딩할 때 특히 헷갈리는 지점입니다. AI가 “마이그레이션을 만들었습니다”라고 말해도 실제 데이터베이스에는 아직 아무 변화가 없을 수 있어요.
보통 작업은 두 단계로 나뉩니다.
- 마이그레이션 생성: 데이터베이스를 어떻게 변경할지 적은 파일을 만듭니다.
- 마이그레이션 적용: 그 파일의 명령을 실제 데이터베이스에서 실행합니다.
설계도를 수정한 것과 실제 공사를 진행한 것이 다른 것과 같아요. 마이그레이션 파일만 생성한 상태에서 앱을 실행하면 코드는 memo 컬럼을 사용하려 하지만 데이터베이스에는 컬럼이 없어서 오류가 날 수 있습니다.
반대로 어느 데이터베이스에 적용했는지도 중요합니다. 내 컴퓨터의 개발용 DB에 적용했다고 해서 실제 서비스의 운영 DB까지 자동으로 바뀌는 것은 아니에요. 프로젝트의 배포 방식에 따라 운영 DB에는 별도의 적용 과정이 필요합니다.
Drizzle로 만든 파일을 main에 올릴 때 운영 DB에 적용하는 실제 설정은 GitHub Actions 운영 DB 마이그레이션 가이드에서 확인할 수 있어요.
개발과 운영이 같은 DB를 바라보면 마이그레이션 테스트가 실제 서비스에 바로 영향을 줄 수 있습니다. 환경별 연결을 나누는 방법은 개발·운영 데이터베이스를 분리해야 하는 이유에서 확인하세요.
따라서 AI에게 다음 세 가지를 확인하는 습관이 좋습니다.
어떤 스키마가 변경되었어? 마이그레이션 파일만 생성한 거야, 아니면 데이터베이스에도 적용한 거야? 적용했다면 개발용 DB와 운영 DB 중 어디에 적용했어?
마이그레이션은 데이터를 모두 지우는 작업이 아니에요
이름 때문에 기존 데이터를 다른 곳으로 옮기거나 데이터베이스를 새로 만드는 작업으로 생각할 수 있어요. 실제로 데이터를 이동하는 작업을 데이터 마이그레이션이라고 부르기도 합니다. 하지만 앱 개발 중 “마이그레이션을 실행한다”는 말은 대개 기존 데이터베이스의 구조를 다음 버전으로 변경한다는 뜻입니다.
컬럼이나 테이블을 추가하는 마이그레이션은 기존 데이터를 그대로 둔 채 구조만 확장할 수 있습니다. 그렇다고 모든 변경이 안전한 것은 아니에요.
- 컬럼을 삭제하면 그 컬럼에 있던 데이터도 사라질 수 있습니다.
- 문자열 컬럼을 숫자로 바꾸면 변환할 수 없는 기존 값 때문에 실패할 수 있습니다.
- 필수 컬럼을 추가하면 기존 행에 넣을 값이 없어 오류가 날 수 있습니다.
- 테이블 이름을 바꾸면 이전 이름을 사용하는 코드가 동작하지 않을 수 있습니다.
특히 운영 중인 앱에는 이미 사용자의 데이터가 들어 있습니다. 빈 데이터베이스에서 잘 실행된 마이그레이션이 운영 DB에서도 안전하다고 단정할 수 없는 이유예요.
기존 데이터가 있다면 여러 단계로 바꿔요
모든 지출에 반드시 통화 단위가 있어야 한다고 해볼게요. 처음부터 currency를 필수 컬럼으로 추가하면 기존 지출에는 값이 없기 때문에 변경이 실패할 수 있습니다.
이럴 때는 한 번에 완성하려 하기보다 나누어 진행할 수 있어요.
- 우선 값이 비어 있어도 되는
currency컬럼을 추가합니다. - 기존 지출에는
KRW같은 적절한 값을 채웁니다. - 앱이 새 지출을 저장할 때 통화 단위도 함께 저장하도록 바꿉니다.
- 모든 행에 값이 생긴 것을 확인한 뒤 필수 컬럼으로 변경합니다.
이처럼 기존 데이터를 새 구조에 맞게 채우는 작업을 백필(backfill)이라고 합니다. 중요한 것은 용어를 외우는 일이 아니라, 구조를 바꿀 때 이미 저장된 데이터가 새 규칙을 지킬 수 있는지 생각하는 거예요.
삭제나 대규모 변경이 포함된다면 적용 전에 백업이 있는지 확인하고, 가능하면 개발용 DB에서 먼저 실행해보는 것이 좋습니다. 마이그레이션 파일도 코드와 함께 Git에 기록하면 어떤 변경이 언제 추가되었는지 추적할 수 있어요.
마이그레이션 파일을 직접 고쳐도 될까요?
아직 어디에도 적용하지 않은 새 마이그레이션이라면 내용을 고쳐 다시 검토할 수 있습니다. 하지만 이미 다른 팀원이나 운영 DB에 적용한 마이그레이션 파일을 나중에 수정하면 문제가 생길 수 있어요.
기존 파일은 실행을 마친 것으로 기록되어 다시 적용되지 않을 수 있고, 아직 실행하지 않은 환경에서는 수정된 내용으로 실행될 수 있습니다. 그러면 같은 마이그레이션 이력을 가진 것처럼 보여도 실제 구조가 달라집니다.
이미 적용한 변경을 다시 고쳐야 한다면 기존 기록을 몰래 바꾸기보다 새로운 마이그레이션을 추가하는 방식이 일반적입니다.
002_add_memo.sql
004_change_memo_length.sql
잘못된 공사 지시서를 나중에 바꿔 끼우는 대신, 다음 공사 기록으로 수정 내용을 남기는 셈이에요.
바이브코딩에서는 실행 전에 이것만 확인하세요
AI가 만든 SQL을 모두 이해해야만 데이터베이스를 사용할 수 있는 것은 아닙니다. 대신 마이그레이션을 적용하기 전에 다음 질문에는 답할 수 있어야 해요.
- 어떤 테이블과 컬럼이 추가·변경·삭제되나요?
- 기존 데이터가 삭제되거나 다른 형태로 바뀌나요?
- 기존 데이터도 새 규칙을 만족하나요?
- 마이그레이션 파일만 만들었나요, 실제 DB에도 적용했나요?
- 개발용 DB와 운영 DB 중 어디에 적용하나요?
- 문제가 생겼을 때 복구할 백업이나 되돌리는 방법이 있나요?
AI에게도 “마이그레이션 해줘”라고만 말하기보다 안전 조건을 함께 알려주는 편이 좋습니다.
expenses테이블에currency컬럼을 추가하는 마이그레이션을 만들어줘. 기존 데이터는 삭제하면 안 돼. 기존 행에는KRW를 채우고, 이후에는 필수값이 되게 해줘. 아직 실제 데이터베이스에는 적용하지 말고, 실행될 SQL과 위험 요소를 먼저 설명해줘.
이렇게 요청하면 파일 생성과 실제 적용을 분리해 검토할 수 있고, 기존 데이터를 어떻게 처리할지도 빠뜨리지 않게 됩니다.
정리
- 스키마는 테이블, 컬럼, 데이터 형태와 관계 등 데이터베이스의 현재 구조입니다.
- 앱 기능이 바뀌면 화면과 코드뿐 아니라 스키마도 바꿔야 할 수 있습니다.
- 마이그레이션은 스키마를 변경하는 명령과 그 변경 이력을 뜻합니다.
- 마이그레이션 파일 생성과 실제 데이터베이스 적용은 서로 다른 단계입니다.
- 개발용 DB에 적용한 변경이 운영 DB에 자동으로 적용되는 것은 아닙니다.
- 컬럼 삭제나 타입 변경은 기존 데이터를 손상시킬 수 있으므로 적용 전에 확인해야 합니다.
- 이미 적용한 마이그레이션은 수정하기보다 새로운 마이그레이션으로 다음 변경을 남기는 편이 안전합니다.
관계형 데이터베이스와 NoSQL 중 어떤 방식을 사용할지 정했다면, 이제 그 구조가 앱과 함께 어떻게 바뀌는지도 알아야 합니다. 스키마는 현재의 설계도이고, 마이그레이션은 그 설계도가 지금 모습이 되기까지의 변경 기록입니다.
인스타그램 @ddukddak.build · 페이스북 뚝딱







