콘텐츠로 이동
Study NoteSupabase

12. Vercel과의 역할 배분

Vercel은 지워도 데이터가 안 사라진다. Supabase를 지우면 사라진다

두 회사 모두 “백엔드도 됩니다”라고 말하기 때문에 생기는 혼란이다. Vercel에는 Functions, 파트너 Postgres/Redis, Blob, Cron이 있고, Supabase에는 Edge Functions, Cron, Queues, Storage, Vector가 있다.

하지만 본질은 명확하게 다르다.

Vercel은 코드를 실행하는 회사이고, Supabase는 상태를 보관하는 회사다.

Vercel = 실행 계층Supabase = 상태 계층
프론트엔드 빌드와 배포데이터 (Postgres)
렌더링 (SSR/SSG/ISR/스트리밍)사용자 신원 (Auth)
CDN과 엣지 캐싱파일 (Storage)
요청 단위로 짧게 사는 서버 코드실시간 연결 (Realtime)
프리뷰 배포와 팀 협업권한 규칙 (RLS)

표의 렌더링 약어는 페이지를 언제 그리느냐의 차이다 — SSR(Server-Side Rendering)은 요청마다 서버에서, SSG(Static Site Generation)는 빌드 때 미리, ISR(Incremental Static Regeneration)은 정적 페이지를 주기마다 다시 그린다.

Vercel

프레임워크 통합 — Next.js를 만든 회사다. App Router, Server Components(RSC), 스트리밍이 최적화되어 있다.

글로벌 CDN — 정적 자산과 캐시된 페이지를 사용자 가까이에서 서빙.

프리뷰 배포 — PR마다 고유 URL. 코드 리뷰의 절반이 여기서 끝난다.

이미지 최적화 · Proxy · 관측성 · 빌드 파이프라인.

Supabase

영속 데이터 — 관계형, 트랜잭션, 제약, 인덱스가 있는 진짜 데이터베이스.

행 단위 권한(RLS) — 접근 경로가 늘어나도 규칙은 한 곳에만 존재한다.

완결된 인증 — 소셜, MFA, SSO, 세션 관리까지 제품으로 제공.

상태 있는 연결(Realtime) — WebSocket은 서버리스 함수가 잘 못 하는 영역이다.

DB 내장 기능 — cron, 큐, 벡터 검색, 외부 데이터 연동.

WebSocket과 영속 연결은 서버리스와 근본적으로 궁합이 나쁘다. Realtime을 Supabase가 맡는 건 취향이 아니라 구조적 필연이다.

기능VercelSupabase판단
서버 함수Route Handler / Server ActionEdge Functions상황에 따라 (아래에서 상세히)
스케줄 작업Vercel Cronpg_cronDB 작업이면 Supabase
큐Vercel QueuespgmqDB 트랜잭션과 묶이면 Supabase
파일 저장BlobStorage권한이 필요하면 Supabase
KV 캐시파트너 Redis(Postgres/외부)세션 캐시는 Vercel 쪽
이미지 최적화next/imageStorage 변환한 쪽만 쓴다 (중복 과금)
인증(직접 구현)AuthSupabase
DB파트너 PostgresPostgresSupabase (통합 이점)
Vercel의 CDN·Proxy·RSC·Route Handler·클라이언트 컴포넌트가 Supabase의 Auth·Postgres·Realtime·Storage·Edge Functions와 어떻게 이어지는지
흐름경로장점
1. 서버 렌더링 조회브라우저 → Vercel(RSC) → Supabase REST → Postgres(RLS)초기 로딩이 빠르고 SEO에 유리. 쿠키의 JWT가 그대로 전달된다
2. 클라이언트 직접 조회브라우저 → Supabase REST → Postgres(RLS)Vercel을 아예 거치지 않는다. 함수 실행 비용이 0
3. 서버 액션 / Route Handler브라우저 → Vercel 함수 → (Supabase + 외부 API)시크릿을 쓸 수 있고 여러 작업을 조율할 수 있다

세 가지를 다 쓰는 게 정상이다. 하나로 통일하려 하지 말 것. 페이지 첫 화면은 1번, 무한 스크롤은 2번, 결제는 3번 — 이런 식으로 섞인다.

서버 코드를 Supabase Edge Function에 둘지 Vercel에 둘지 — DB 이벤트·배포 수명주기·공유 로직·Node 전용 패키지를 차례로 묻는 결정 트리

기본값은 Vercel이다. 이미 그 레포에서 개발하고 배포하고 있기 때문이다. Supabase Edge Function은 “이유가 있을 때” 선택한다.

Vercel Route HandlerSupabase Edge Function
런타임Node.js 또는 EdgeDeno
배포 단위프론트엔드와 함께독립
코드 위치같은 레포, 같은 타입supabase/functions/
타입 공유○ (같은 프로젝트)별도 관리 필요
DB 근접성리전 설정에 따름기본은 사용자 근접, DB 작업이면 리전 지정 필요
프리뷰 배포PR마다 자동브랜치 연동 필요
DB 웹훅 대상가능하지만 우회적자연스러움
Node 패키지전부 사용 가능제한적
시크릿 관리Vercel 환경 변수supabase secrets
하는 일배치이유
상품 목록 페이지 렌더링Vercel RSC렌더링과 조회가 붙어 있다
무한 스크롤 추가 로딩브라우저 → Supabase 직접Vercel 함수 비용 절약
결제 세션 생성Vercel Route HandlerStripe 시크릿 + 프론트 흐름과 결합
Stripe 웹훅 수신Supabase Edge Function프론트 배포와 무관하게 살아야
회원가입 시 프로필 생성Postgres 트리거DB 안에서 원자적으로
가입 환영 메일Supabase Edge FunctionDB 이벤트가 트리거
채팅 메시지 수신Supabase RealtimeWebSocket은 서버리스가 못 한다
이미지 업로드브라우저 → Storage 직접Vercel 함수 본문 크기 제한 회피
야간 집계 배치pg_cronDB 안에서 완결
OG 이미지 생성Vercel프레임워크 기능
supabase.from('posts').select()
  • HTTP라서 커넥션 풀 걱정이 없다
  • RLS가 자동 적용된다
  • 브라우저에서도 동일하게 사용
  • 복잡한 쿼리는 RPC로 내려간다

적합한 곳: 사용자가 자기 데이터를 다루는 모든 경로.

리전 · 캐싱 · 환경 변수 · 프리뷰

섹션 제목: “리전 · 캐싱 · 환경 변수 · 프리뷰”
서울 사용자가 서울 리전 Vercel 함수를 거치면 DB까지 5ms, 워싱턴 리전을 거치면 왕복마다 180ms가 붙는다

함수와 DB가 멀면 왕복마다 대가를 치른다. 한 페이지에 쿼리 5개면 5배로 곱해진다.

{ "functions": { "app/api/**/*.ts": { "maxDuration": 30 } }, "regions": ["icn1"] }

Edge 런타임은 사용자에게는 가깝지만 DB에서는 멀 수 있다. DB를 많이 읽는 라우트는 Node 런타임 + DB 리전이 낫다. Supabase Edge Function도 기본은 사용자와 가까운 리전에서 실행되므로, DB 왕복이 많은 함수는 호출할 때 Database 리전을 명시한다.

담당무엇을
Vercel정적 자산과 빌드 결과물(CDN), ISR/revalidate 페이지 캐시, Data Cache와 태그 무효화
SupabaseStorage 파일의 CDN 캐시(cacheControl), 이미지 변환 결과 캐시
터미널 창
# Vercel — 클라이언트에도 노출 (브라우저 번들 포함)
NEXT_PUBLIC_SUPABASE_URL=https://<ref>.supabase.co
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=sb_publishable_xxx
# Vercel — 서버 전용
SUPABASE_SECRET_KEY=sb_secret_xxx
STRIPE_SECRET_KEY=sk_live_xxx
DATABASE_URL=postgres://...pooler.supabase.com:6543/postgres # 직접 연결용
# Supabase — Edge Function 전용
supabase secrets set RESEND_API_KEY=re_xxx

NEXT_PUBLIC_ 접두사 = 공개라고 외운다. 여기 secret이 들어가면 즉시 사고다.

Vercel과 Supabase를 잇는 방법은 두 가지다 — Vercel Marketplace 네이티브 통합(리소스를 Vercel 안에서 관리, 통합 청구)과 수동 연결(Supabase에서 프로젝트를 만들고 키를 환경 변수에 붙여넣기). 팀이 이미 Supabase 대시보드를 쓰고 있다면 후자가 자연스럽다.

PR을 만들면 Vercel 프리뷰와 Supabase Preview Branch가 생기고 환경 변수가 주입되며, 머지하면 프로덕션 배포와 브랜치 정리가 일어난다
  • 각 PR이 자체 DB를 갖는다 — 스키마 변경을 안전하게 테스트할 수 있다
  • 프리뷰 브랜치는 데이터를 복사하지 않는다. 시드 파일로 채워야 한다
  • 프리뷰 브랜치는 시간당 과금된다 — 오래된 브랜치를 정리한다

프리뷰 배포에서 소셜 로그인이 깨지는 대표적 원인이다. Vercel 프리뷰 URL은 배포마다 바뀌는데(myapp-git-feat-x-team.vercel.app), Supabase의 Redirect URL 허용 목록에 없으면 로그인 후 리다이렉트가 거부된다.

# 해결 1: 와일드카드 등록
https://*-myteam.vercel.app/**
https://myapp-*.vercel.app/**
// 해결 2: 콜백에서 원래 주소로 되돌리기
const origin = request.headers.get('origin')
const forwardedHost = request.headers.get('x-forwarded-host') // Vercel이 붙여준다
const redirectBase = process.env.NODE_ENV === 'development'
? origin
: `https://${forwardedHost}`

해결 3: 프리뷰에도 고정 도메인을 할당한다 (브랜치별 별칭 도메인).

역할 배분을 이해해도 첫 배포에는 Google OAuth callback, Supabase Auth 허용 목록, Vercel 환경별 변수, Cloudflare DNS처럼 여러 제어판을 의존 순서대로 맞추는 작업이 남는다. 이 절차와 실제 timeline issue #8에서 확인한 함정은 실전 가이드 — Supabase 앱 첫 배포에 분리했다.

Vercel의 비용 동인Supabase의 비용 동인
함수 실행 시간과 호출 수컴퓨트 크기 (상시 과금)
대역폭 (전송량)대역폭 (egress)
이미지 최적화 횟수스토리지 용량
빌드 시간MAU(Monthly Active Users — 월간 활성 사용자), 브랜치 시간

돈이 되는 판단들 —

  • 클라이언트에서 Supabase로 직접 조회하면 Vercel 함수 비용이 0이다
  • 반대로 모든 조회를 RSC로 하면 Vercel 함수 실행 시간이 늘어난다
  • 이미지 최적화는 한 쪽에서만 한다
  • 파일은 브라우저에서 Storage로 직접 올린다 — Vercel 대역폭을 소비하지 않는다
나쁜 업로드는 파일이 Vercel 함수를 거쳐 가고, 좋은 업로드는 서명 URL을 받아 브라우저가 Storage로 직접 보낸 뒤 완료를 알린다

나쁜 경로의 문제는 요청 본문 크기 제한, 함수 실행 시간 제한, 양쪽 대역폭 이중 과금이다. 좋은 경로에서 서버는 권한 판단과 기록만 하고 바이트는 지나가지 않는다.

Supabase는 Vercel 전용이 아니다.

  • Cloudflare Pages / Workers — 엣지 실행, 저렴한 대역폭
  • Netlify — Vercel과 유사한 모델
  • Fly.io / Railway / Render — 상시 실행 서버. 커넥션 풀을 직접 관리할 수 있어 ORM 직접 연결에 유리하다
  • 모바일 앱 — 프론트엔드가 아예 없다. Supabase가 유일한 백엔드
  • 정적 사이트 + 클라이언트 전용 — Astro/Vite SPA가 브라우저에서 직접 호출

상시 실행 서버를 쓴다면 서버리스 특유의 제약(커넥션 폭발, 콜드 스타트, WebSocket 불가)이 사라진다. 그 경우 Supabase를 “그냥 관리형 Postgres”로만 써도 충분히 합리적이다.

  1. 모든 조회를 Vercel 함수로 프록시 — 지연 시간과 비용이 두 배
  2. secret key로 서버에서 전부 처리하고 RLS를 안 씀 — 권한 로직이 앱 코드로 흩어진다
  3. 함수 리전과 DB 리전이 대륙 단위로 다름 — 가장 흔한 성능 문제
  4. Prisma 직접 연결에 RLS를 기대 — 적용되지 않는다
  5. 프리뷰와 프로덕션이 같은 DB — 프리뷰에서 프로덕션 데이터를 지운다
  6. 프리뷰 URL을 Redirect 목록에 안 넣음 — 로그인 테스트가 불가능해진다
  7. 파일을 Vercel 함수로 중계 — 크기 제한과 이중 과금
  8. next/image와 Storage 변환을 동시에 — 양쪽에 과금
  9. 사용자별 데이터를 ISR 캐시에 저장 — 데이터 유출
  10. Direct host(db.<ref>.supabase.co:5432)로 서버리스 배포 — 커넥션 고갈
  • Vercel = 실행, Supabase = 상태. 이 한 줄이 대부분의 판단을 해결한다
  • 서버 로직의 기본값은 Vercel, DB 이벤트가 트리거이거나 프론트 배포와 분리돼야 하면 Supabase
  • 사용자 데이터 CRUD는 Data API + RLS, 관리자·배치는 직접 연결
  • 리전을 맞춘다. 함수와 DB가 멀면 모든 쿼리에 세금이 붙는다
  • 파일과 실시간은 브라우저 ↔ Supabase 직접 연결이 정답이다
  • 프리뷰 환경은 별도 브랜치로 분리하고, Redirect URL 와일드카드를 잊지 않는다