Supabase 무료 플랜, 로컬에서 DB 연결이 안 되는 진짜 이유
Supabase 무료 플랜에서 로컬 개발 시 DB 연결이 안 되는 이유를 파헤쳤다. IPv4/IPv6 문제부터 Prisma v7 설정 변경, dotenv 함정까지 — 삽질한 것들을 모두 정리했다.
갑자기 DB 연결이 안 된다
Next.js + Prisma + Supabase 조합으로 새 프로젝트를 시작했다.
Supabase 대시보드에서 연결 주소를 복사해서 .env에 붙여넣었다.
DATABASE_URL="postgresql://postgres:password@db.xxx.supabase.co:5432/postgres"
개발 서버를 켰는데 바로 에러가 났다.
getaddrinfo ENOTFOUND db.xxx.supabase.co
DB 주소를 못 찾겠다는 에러다. 입력을 잘못한 줄 알고 몇 번을 다시 복사했지만 계속 똑같이 터졌다.
원인 — IPv4 vs IPv6
인터넷 주소 체계가 두 가지다.
- IPv4 → 우리가 흔히 아는 방식. 한국 가정 인터넷 거의 전부가 이걸 쓴다.
- IPv6 → 최신 방식. 아직 일반 가정에서는 잘 지원 안 된다.
Supabase 무료 플랜(Free Plan)의 DB 서버는 IPv6 주소만 갖고 있다.
그래서 IPv4를 쓰는 일반 가정 인터넷에서는 주소 자체를 찾지 못한다. DNS 응답이 없다.
Supabase 대시보드 Connect 버튼을 눌러보면 작은 글씨로 이런 경고가 있다.
"Not IPv4 compatible — Use Session Pooler if on a IPv4 network"
처음에는 이게 뭔 말인지 몰랐다. 지나쳤다.
왜 이렇게 만들어 놨을까
Supabase 입장에서는 비용 문제다.
IPv4 주소는 현재 개당 몇 달러씩 구매해야 한다. 수십만 개의 무료 프로젝트에 전부 IPv4를 붙이면 비용이 엄청나다.
IPv6는 사실상 무제한 무료다.
그래서 무료 플랜 유저에게는 IPv6만 준다. 유료 플랜($25/월)으로 업그레이드하거나 IPv4 Add-on을 별도 구매하면 Direct Connection이 IPv4로도 된다.
Session Pooler를 시도했지만 또 막혔다
Direct Connection 대신 Session Pooler URL을 써보라는 Supabase 안내를 따랐다.
DATABASE_URL="postgresql://postgres.xxx:password@aws-0-ap-northeast-2.pooler.supabase.com:5432/postgres"
이번엔 다른 에러가 났다.
Tenant or user not found
비밀번호가 틀렸나 싶어서 비밀번호 URL 인코딩도 해보고, 새 DB 유저도 만들어봤다. 다 소용없었다.
이 에러는 비밀번호 문제가 아니다.
PgBouncer(Supabase의 연결 풀러)가 이 프로젝트를 아직 모른다는 뜻이다. 비밀번호를 확인하기도 전 단계에서 터진다.
Supabase는 새로 생성된 프로젝트를 지역별 공유 풀러 서버에 등록하는 과정이 있는데, 이게 즉각적이지 않다. 프로젝트 생성 후 몇 시간에서 수십 시간이 걸릴 수 있다.
최종 해결 — 로컬 PostgreSQL 설치
클라우드 연결을 고집할 이유가 없었다. 로컬 개발 환경이니까 로컬 DB를 쓰는 게 맞다.
1# PostgreSQL 설치 2brew install postgresql@16 3brew services start postgresql@16 4 5# 개발용 DB 및 유저 생성 6createdb mooda 7psql postgres -c "CREATE USER mooda_dev WITH PASSWORD 'mooda_dev' CREATEDB;" 8psql postgres -c "GRANT ALL PRIVILEGES ON DATABASE mooda TO mooda_dev;" 9psql mooda -c "ALTER SCHEMA public OWNER TO mooda_dev;"
.env도 간단하게 바꿨다.
DATABASE_URL="postgresql://mooda_dev:mooda_dev@localhost:5432/mooda"
1npx prisma migrate dev --name init
연결 성공.
Prisma v7에서 추가로 막힌 것
Prisma 버전 7로 올라오면서 설정 방식이 바뀌었다.
기존 방식 (v5~v6)
1datasource db { 2 provider = "postgresql" 3 url = env("DATABASE_URL") 4}
v7 방식 — schema.prisma에서 URL을 제거하고 prisma.config.ts 파일로 분리
1// prisma.config.ts 2import 'dotenv/config'; 3import { defineConfig, env } from 'prisma/config'; 4 5export default defineConfig({ 6 schema: 'prisma/schema.prisma', 7 migrations: { 8 path: 'prisma/migrations', 9 }, 10 datasource: { 11 url: env('DATABASE_URL'), // CLI 마이그레이션용 12 }, 13});
1// src/lib/prisma.ts — 런타임용 (앱 실행 중 DB 연결) 2import { PrismaClient } from '@prisma/client'; 3import { PrismaPg } from '@prisma/adapter-pg'; 4import { Pool } from 'pg'; 5 6function createPrismaClient() { 7 const pool = new Pool({ connectionString: process.env.DATABASE_URL }); 8 const adapter = new PrismaPg(pool); 9 return new PrismaClient({ adapter }); 10} 11 12export const prisma = globalForPrisma.prisma ?? createPrismaClient();
마이그레이션(CLI)용 URL과 런타임(앱 실행)용 연결을 완전히 분리해서 설정한다.
.env vs .env.local — dotenv 함정
prisma.config.ts에 import 'dotenv/config'를 넣었는데 환경변수를 못 찾는 에러가 났다.
PrismaConfigEnvError: Cannot resolve environment variable: DATABASE_URL
원인은 간단했다.
dotenv는.env파일만 읽는다.env.local은 Next.js 전용 파일이다. Next.js 런타임에서만 자동으로 로드된다- Prisma CLI는 Node.js로 직접 실행되므로
.env.local을 무시한다
해결: Prisma CLI 전용으로 .env 파일을 따로 만들었다.
# .env — Prisma CLI 전용
DATABASE_URL="postgresql://mooda_dev:mooda_dev@localhost:5432/mooda"
# .env.local — Next.js 앱 전용
DATABASE_URL="postgresql://mooda_dev:mooda_dev@localhost:5432/mooda"
# 프로덕션용은 주석 처리
# DATABASE_URL="postgresql://postgres.xxx:password@aws-0-ap-northeast-2.pooler.supabase.com:5432/postgres"
정리
| 문제 | 원인 | 해결 |
|---|---|---|
| Direct Connection DNS 응답 없음 | Supabase 무료 플랜은 IPv6 전용 | 로컬 PostgreSQL 사용 |
| Session Pooler "Tenant or user not found" | 신규 프로젝트 풀러 등록 지연 | 로컬 PostgreSQL 사용 |
| Prisma migrate dev 실패 | v7에서 prisma.config.ts 방식 변경 | datasource.url로 URL 분리 |
| dotenv가 DATABASE_URL 못 찾음 | .env.local은 dotenv가 읽지 않음 | .env 파일 별도 생성 |
Supabase 무료 플랜은 로컬 개발에서 바로 연결하기 어렵다.
로컬 개발에는 로컬 PostgreSQL을 쓰고, EC2나 서버에 배포할 때 Supabase와 연결하는 방식이 훨씬 안정적이다. EC2는 데이터센터 환경이라 IPv6 연결이 되고, 그 시점엔 Session Pooler 등록도 완료돼 있을 것이다.