TechFeedTechFeed
Backend

Prisma P2021, 테이블 없음, migrate | 프리뷰 DB에 스키마가 없으면?

로컬은 되고 버셀 프리뷰만 테이블이 없으면 P2021입니다. generate는 클라이언트만 만들고, 스키마는 migrate deploy가 넣습니다. db push는 로컬 초안용입니다. 프리즈마, 넥스트, 슈퍼베이스, 버셀 프리뷰, PostgreSQL, 백엔드, 1인 개발자 기준. 2026년 9월 프리즈마·버셀 공식 문서.

by

P2021은 지금 붙은 데이터베이스에 그 테이블이 없어서입니다. 로컬은 되고 버셀 프리뷰만 The table does not exist in the current database가 뜨면, 클라이언트 생성이 아니라 마이그레이션이 그 주소에 안 들어간 겁니다.


혼자 넥스트와 슈퍼베이스를 붙이다 보면 로컬에서 migrate dev로 표를 만들고, 프리뷰는 빈 디비에 generate만 돌린 채 화면을 올리는 일이 납니다. 타입은 생기니 빌드는 초록이고, 첫 조회에서야 테이블이 없다고 죽습니다.


프리뷰 환경 변수에 붙은 주소로 migrate deploy를 넣고, db push는 로컬 초안용으로 남기면 됩니다. 근거는 프리즈마 에러 코드버셀 배포 안내에 있습니다.


P2021이 뜨면 어디를 보나

붙은 주소의 데이터베이스에 그 표가 있는지부터 봅니다. 프리즈마 클라이언트가 쿼리를 날릴 때 엔진이 테이블을 못 찾으면 P2021을 던집니다. 메시지는 The table `User` does not exist in the current database처럼, 모델 이름이나 매핑된 표 이름을 넣습니다.


빌드가 초록인 것과 표가 있는 것은 다른 일입니다. prisma generate는 타입과 클라이언트를 만들고, 데이터베이스에 CREATE TABLE을 넣지 않습니다. 그래서 프리뷰 배포가 성공한 뒤 카카오 로그인 직후 사용자 조회에서만 죽을 수 있습니다.


권한으로 막힌 줄과 자리가 다릅니다. 표는 있는데 넣기만 거절되면 슈퍼베이스 행 수준 보안 칸입니다. 표 자체가 없으면 정책이 아니라 스키마입니다. 유니크 충돌 P2002도 표가 있는 뒤의 이야기라, 여기서는 테이블 없음만 봅니다.


먼저 기억할 것 | 로컬 스튜디오에 표가 보여도 프리뷰가 읽는 주소가 같다는 뜻은 아닙니다. 에러의 meta.table과 프리뷰 DATABASE_URL의 호스트, 디비 이름부터 나란히 보세요.


로컬 데이터베이스에는 테이블이 있고 프리뷰 빈 데이터베이스에는 없어서 P2021이 나는 개념 이미지
클라이언트는 생겼는데 프리뷰 디비에 표가 없으면 첫 조회에서 P2021이 난다

generate와 migrate와 db push가 하는 일

세 명령이 만지는 칸이 다릅니다. 한 칸만 고치면 다른 칸이 비어 있으니, 누가 성공했는지를 표로 가릅니다.


명령무엇을 하나프리뷰에서
prisma generate클라이언트와 타입만 만듦빌드는 초록, 표는 그대로 없음
prisma migrate deploy대기 중인 마이그레이션 SQL을 적용프리뷰·운영에 넣을 명령
prisma db push스키마를 디비에 바로 맞춤. 이력 파일 없음로컬 초안용. 공유 디비에 비권장
prisma migrate dev파일 생성, 적용, 클라이언트 생성. 섀도 디비 사용개발 머신 전용. CI에 넣지 말 것
prisma migrate status적용됨·대기 중을 표시표가 없는 이유를 먼저 확인

공식 프로토타이핑 문서도 db push는 마이그레이션 이력을 만들지 않고, 다른 환경에 같은 변경을 재현하려면 마이그레이션을 쓰라고 적습니다. 로컬에서 푸시만 반복하다가 프리뷰에 파일이 없으면, 배포 단계에 migrate deploy를 넣어도 적용할 SQL이 없습니다.


제가 쓰는 사이트는 드리즐 쪽이지만, 옆 프로젝트에서 프리즈마를 붙였을 때 같은 함정에 걸렸습니다. 맥에서 스튜디오가 열려 있으니 표가 있다고 착각하고, 프리뷰만 빈 네온 디비를 보고 있었습니다.


P2021 메시지와 상태 확인
// PrismaClientKnownRequestError // code: 'P2021' // message: The table `User` does not exist in the current database. npx prisma migrate status # Database schema is up to date 가 아니면 대기가 남은 것 # 프리뷰 URL을 잠깐 넣어서 상태를 본다 DATABASE_URL="$PREVIEW_DATABASE_URL" npx prisma migrate status

프리뷰 DB가 비어 있는 이유

프리뷰가 운영과 같은 변수를 쓰거나, 새 디비를 만들고 마이그레이션을 안 넣으면 비어 있습니다. 버셀은 풀 리퀘스트마다 프리뷰 환경을 만듭니다. 프로젝트 가져오기 때 넣은 DATABASE_URL이 운영과 프리뷰에 같이 붙어 있으면, 프리뷰가 운영 스키마를 건드리거나, 반대로 운영만 채워지고 프리뷰 전용 디비는 빈 채로 남습니다.


프리즈마 버셀 안내도 프리뷰용 두 번째 호스티드 데이터베이스를 두고, 대시보드에서 프리뷰 환경에만 그 주소를 넣으라고 적습니다. 스키마 마이그레이션이 있는 풀 리퀘스트가 운영 표를 바꾸지 않게 하려는 이유입니다. 주소를 나눈 뒤에는 그 빈 디비에 migrate deploy가 돌아가야 표가 생깁니다.


네온 브랜치를 쓰면 부모 스키마를 복사해 주는 상품도 있습니다. 복사 없이 빈 프로젝트만 만들면 로컬과 이름이 같아도 표는 없습니다. 슈퍼베이스도 프리뷰용 프로젝트를 따로 두면 로컬 migrate dev 이력이 거기 없습니다. 한국에서 1인으로 카카오 콜백을 프리뷰 도메인에 넣을 때, 사용자 표가 없어서 콜백이 500으로 끝나는 패턴이 여기입니다.


사람 없이 파란 표시등이 켜진 서버 랙 통로
프리뷰 전용 디비를 나누면 운영 표는 남고, 빈 주소에는 마이그레이션을 따로 넣어야 한다

빌드에 migrate deploy를 넣는 순서

클라이언트 생성 다음, 넥스트 빌드 앞에 배포용 마이그레이션을 넣습니다. 프리즈마 버셀 문서는 postinstallprisma generate를 두고, 스키마까지 맞추려면 prisma generate && prisma migrate deploy && next build 같은 빌드 스크립트를 안내합니다. generate만 있으면 타입은 맞고 표는 없습니다.


migrate deploy는 개발용 migrate dev와 달리 드리프트를 보지 않고, 디비를 리셋하지 않고, 섀도 디비를 쓰지 않습니다. 대기 중인 파일을 순서대로 적용합니다. 파일이 저장소에 커밋돼 있어야 프리뷰 러너가 같은 SQL을 돌립니다. 로컬에서만 푸시하고 파일을 안 올리면 배포 단계는 할 일이 없습니다.


연결은 직접 주소가 필요합니다. 슈퍼베이스 트랜잭션 풀러는 마이그레이션 세션에 안 맞을 수 있어, 스키마 변경은 directUrl 쪽을 쓰는 구성이 흔합니다. 앱 쿼리는 풀 주소를 쓰고, 배포 단계만 직접 주소로 migrate deploy를 돌리면 표가 생깁니다. 풀 주소로 배포 단계가 실패하면 빌드는 지나갔는데 런타임만 P2021인 상태로 남습니다.


버셀 빌드에 생성과 배포 마이그레이션을 같이
{ "scripts": { "postinstall": "prisma generate", "vercel-build": "prisma generate && prisma migrate deploy && next build" } } # 버셀 프로젝트 Build Command 를 npm run vercel-build 로 둔다 # PREVIEW / PRODUCTION 각각 DATABASE_URL 을 나눈 뒤 # 프리뷰 주소로 migrate status 가 초록인지 한 번 확인

db push를 프리뷰에 쓰면 안 되는 자리

공유하는 프리뷰 디비에는 이력 없는 푸시를 넣지 않습니다. db push는 스키마 엔진으로 디비를 스키마 파일에 맞추고, _prisma_migrations를 만들거나 갱신하지 않습니다. 미리보기도 없고, 데이터 손실이 보이면 --accept-data-loss를 요구합니다. 컬럼 이름 바꾸기처럼 드롭 후 생성이 되면 프리뷰에 쌓인 테스트 행이 사라질 수 있습니다.


로컬에서 초안을 잡은 뒤에는 migrate dev로 파일을 남기고, 다른 환경은 그 파일만 적용합니다. 푸시와 마이그레이션을 섞으면 드리프트가 납니다. 개발 명령이 리셋을 물어 보는 이유가 그 이력과 실제 표가 갈렸기 때문입니다. 프리뷰에 푸시를 한 번 넣으면, 이후 migrate deploy가 같은 변경을 다시 적용하려다 실패하거나, 반대로 이미 표가 있어 파일이 대기 중으로 남는 식이 됩니다.


플래닛스케일처럼 문서가 푸시를 권하는 호스트는 예외로 적혀 있습니다. 포스트그레 슈퍼베이스나 네온을 버셀 프리뷰에 붙인 1인 구성은 파일 이력이 있는 쪽이 재현됩니다. 운영에 푸시를 넣는 습관은 롤백 파일이 없어서, 카카오 사용자 표 컬럼을 잘못 지웠을 때 되돌릴 칸이 없습니다.


함정 | 로컬에서 db push로 표가 생겼다고 프리뷰가 따라오지는 않습니다. 저장소의 prisma/migrations에 같은 변경이 파일로 있어야 배포 단계가 따라갑니다.


DATABASE_URL이 다른 칸을 가리킬 때

표가 있는 디비가 아니라 빈 디비를 보고 있으면 같은 코드가 납니다. 호스트는 맞는데 데이터베이스 이름만 다르거나, 스키마가 public이 아닌데 클라이언트가 public만 보는 경우입니다. @@map으로 표 이름을 바꿨으면 메시지에 찍힌 이름과 실제 포스트그레 표 이름을 대조하세요.


증상먼저 볼 것고칠 칸
로컬만 되고 프리뷰만 P2021프리뷰 DATABASE_URL, migrate status프리뷰 전용 디비 + migrate deploy
빌드는 초록, 첫 API만 죽음postinstall이 generate만인지vercel-build에 migrate deploy
스튜디오엔 표가 있음스튜디오가 연 주소와 앱 주소같은 호스트·디비 이름인지
migrate deploy가 실패풀러 URL, 권한, 직접 주소directUrl로 배포 단계
컬럼만 없음에러 코드가 P2022인지테이블 없음 글이 아님

포스트그레에서 표 목록을 직접 보면 추측이 줄어듭니다. pg_tablesschemanamepublic인지, 메시지에 찍힌 이름이 거기에 있는지 확인합니다. 행 수준 보안으로 조회가 빈 배열인 것과 달리, P2021은 예외를 던집니다. 문의 저장이 안 끝나고 풀이 차는 줄은 문장 제한 칸이고, 표가 없는 줄과는 다릅니다.


컬럼이 없는 P2022는 표는 있고 필드만 빠진 상태입니다. 마이그레이션 파일이 중간에 커밋되지 않았거나, 예전 프리뷰 디비에 일부만 적용된 경우입니다. 코드가 P2021이면 표 자체부터 맞추고, 그다음에 컬럼을 봅니다.


프리뷰 디비에 표가 있는지 직접 확인
-- 프리뷰에 붙은 주소로 접속한 뒤 SELECT schemaname, tablename FROM pg_tables WHERE schemaname = 'public' ORDER BY tablename; -- 모델 User 가 @@map("users") 이면 users 가 있어야 한다 -- 목록이 비면 migrate deploy 가 그 주소에 안 들어간 것
코드 편집기와 미리보기 화면이 켜진 모니터 두 대의 개발 책상
로컬 스튜디오가 초록이어도 프리뷰가 읽는 주소에 표가 있는지는 따로 확인한다

참고한 공식 문서


내부 연계: 드리즐과 프리즈마, 조회는 되고 넣기만 403, 소프트 삭제와 부분 유니크, 문장 제한과 유휴, 오토배큠


인용한 동작은 2026년 9월 프리즈마 7 공개 문서 기준입니다. 프리즈마 8은 CLI 이름이 달라질 수 있어, 에러 코드 P2021이 나는 클라이언트 버전 기준으로 명령을 확인하세요.


자주 묻는 질문

prisma generate만 하면 표가 생기나요?

생기지 않습니다. generate는 클라이언트와 타입만 만듭니다. 표는 migrate deploy나 로컬의 migrate dev, 초안의 db push가 넣습니다.


프리뷰에 db push를 넣으면 끝나나요?

표는 생길 수 있습니다. 이력 파일이 없고 미리보기도 없어서, 다음 배포의 migrate deploy와 어긋나기 쉽습니다. 공유 프리뷰는 파일 적용이 맞습니다.


로컬 스튜디오에 표가 보이면 프리뷰도 있는 건가요?

아닙니다. 스튜디오가 연 주소와 프리뷰 환경 변수가 다를 수 있습니다. 프리뷰 URL로 migrate status와 pg_tables를 보세요.


P2021과 403 행 수준 보안은 어떻게 나누나요?

표가 없으면 P2021 예외입니다. 표는 있고 넣기만 거절되면 정책 칸입니다. 조회가 빈 배열인 것과 테이블 없음 예외를 같은 줄로 보지 마세요.


마이그레이션 파일이 저장소에 없으면요?

migrate deploy는 적용할 SQL이 없습니다. 로컬 푸시만으로는 프리뷰가 따라오지 않습니다. migrate dev로 파일을 커밋한 뒤 배포 단계에 넣으세요.


컬럼이 없다는 메시지면 같은 글인가요?

아닙니다. 그건 P2022입니다. 표는 있고 필드만 빠진 상태라, 대기 중인 마이그레이션이나 일부만 적용된 프리뷰 디비를 봅니다.


프리뷰의 P2021은 빈 디비에 마이그레이션이 안 들어간 상태입니다. generate로 빌드를 초록으로 만들어도 표는 생기지 않고, db push는 로컬 초안에 남기면 됩니다. 관련 글: 드리즐과 프리즈마, RLS 넣기 403, 소프트 삭제.


PrismaP2021migratedb push테이블 없음프리뷰슈퍼베이스버셀PostgreSQL넥스트백엔드마이그레이션개발자

함께 보면 좋은 문제 해결

EXPLORE / Backend

이어서 읽어보기

전체 토픽 둘러보기