블로그 목록
인프라데이터베이스

Railway로 PostgreSQL 띄우기 — Vercel 배포 프로젝트에 DB 붙이는 법

개인 프로젝트에 DB가 필요해졌다. 선택지를 몇 개 놓고 고민했다.

Supabase는 많이 쓰는데 무료 플랜이 2주 이상 비활성이면 인스턴스를 멈춰버린다. 개인 사이드 프로젝트 특성상 트래픽이 일정하지 않으니까 좀 불안했다. PlanetScale은 MySQL 계열이고, 얼마 전에 무료 플랜을 없앴다. Neon은 PostgreSQL 서버리스인데 콜드 스타트가 있다.

Railway는 사용한 만큼만 과금하는 구조인데, PostgreSQL 하나 돌리는 비용이 한 달에 몇 달러 수준이라서 개인 프로젝트용으로 부담이 없었다. 거기다 UI가 깔끔하고, 설정이 별로 없다는 게 마음에 들었다.

DB 생성

Railway 대시보드에서 New Project → Database → PostgreSQL 선택하면 1분도 안 걸려서 인스턴스가 올라온다. 별도의 설정 없이 바로 쓸 수 있는 상태가 된다.

생성하고 나면 Variables 탭에서 접속 정보가 다 나온다.

접속 URL 두 개를 구분해야 한다

Railway PostgreSQL에서 처음에 헷갈렸던 부분이 이거다. 접속 URL이 두 종류다.

  • DATABASE_URLpostgres.railway.internal 도메인. Railway 내부 네트워크에서만 접근 가능.
  • DATABASE_PUBLIC_URLturntable.proxy.rlwy.net 같은 도메인. 외부에서 접근 가능.

Vercel에 배포된 앱은 Railway 내부망이 아니니까, 프로덕션에서는 DATABASE_PUBLIC_URL을 써야 한다. 로컬 개발할 때도 마찬가지.

근데 Railway 내부에서 돌아가는 앱이 있다면 내부 URL을 쓰는 게 빠르고 보안상 낫다. 내가 쓴 경우엔 Vercel + Railway 조합이라 Public URL만 씀.

Variables 탭에서 DATABASE_PUBLIC_URL 옆에 느낌표 아이콘이 있는데, 클릭하면 전체 URL을 복사할 수 있다. 처음엔 이걸 못 찾고 헤맸다.

Prisma 연결

ORM은 Prisma를 썼다. schema.prisma의 datasource 설정과 .env 파일에 URL 넣는 게 기본 흐름이다.

// .env
DATABASE_URL="postgresql://postgres:비밀번호@turntable.proxy.rlwy.net:포트/railway"

Prisma 7 버전부터는 드라이버 어댑터 구조로 바뀌어서 설정 방식이 좀 달라졌다. 기존처럼 datasourceUrl을 생성자에 바로 넣는 게 안 된다.

// lib/prisma.ts
import { PrismaClient } from './generated/prisma/client';
import { PrismaPg } from '@prisma/adapter-pg';

function createPrismaClient() {
  const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
  return new PrismaClient({ adapter });
}

const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
export const prisma = globalForPrisma.prisma ?? createPrismaClient();
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;

@prisma/adapter-pg를 별도로 설치해야 한다.

npm install @prisma/adapter-pg

Vercel 배포 시 주의사항

Prisma는 prisma generate를 실행해야 클라이언트 코드가 생성된다. 로컬에서는 한 번 실행해두면 되는데, Vercel 배포 환경에서는 매번 새로 빌드하니까 빌드 전에 generate를 실행해줘야 한다.

package.json의 build 스크립트에 추가하거나, 별도 빌드 스크립트를 만들어서 처리한다.

# scripts/build.sh
npx prisma generate
next build

이걸 안 해두면 Cannot find module './generated/prisma/client' 에러로 배포가 터진다. lib/generated/ 디렉토리가 .gitignore에 들어있으니 당연한 결과인데, 처음엔 왜 로컬에선 되는데 배포에서 안 되는지 바로 안 보여서 좀 걸렸다.

로컬 개발 환경 설정

prisma.config.ts를 쓰는 경우 Prisma CLI가 .env.local을 읽지 않는다는 것도 알아둬야 한다. dotenv/config는 기본적으로 .env를 읽으니까, .env에도 DATABASE_URL을 넣어줘야 prisma migrate dev 같은 명령어가 제대로 동작한다.

.env는 로컬 개발 전용 접속 정보, .env.local은 Next.js 앱에서 쓰는 환경변수 — 이렇게 역할을 분리해서 관리하면 혼선이 없다.

데이터 확인

Railway 대시보드에서 Data 탭 들어가면 테이블과 레코드를 GUI로 볼 수 있다. psql 접속이나 별도 클라이언트 없이도 간단한 확인은 여기서 된다.

Prisma Studio를 쓰는 것도 편하다.

npx prisma studio

로컬에서 localhost:5555로 열리는 GUI인데, 개발 중에 데이터 확인하거나 직접 레코드 추가할 때 유용하다.


설정이 생각보다 단순해서 처음 세팅에 30분도 안 걸렸다. 주의할 점은 internal URL vs public URL 구분, 그리고 Vercel 배포 시 prisma generate 빠뜨리지 않는 것 정도다.