시리즈 목차 1편 👉 Supabase란 무엇인가? Firebase와 제대로 비교해보기 (현재 글) 2편 – 데이터베이스 & 자동 API (REST/GraphQL) 3편 – 인증(Auth) — 소셜 로그인, JWT, SSO, SAML 4편 – RLS 보안 — Row Level Security 완벽 가이드 …
들어가며
백엔드 없이 서비스를 만들고 싶다면, 요즘 개발자들이 가장 먼저 떠올리는 두 가지 선택지가 있습니다. 바로 Firebase와 Supabase입니다.
Firebase는 2011년 등장해 구글에 인수된 이후 오랫동안 BaaS(Backend as a Service)의 대명사였습니다. 수많은 스타트업이 Firebase 위에서 빠르게 MVP를 만들고 성장했죠. 그런데 2020년, 조용히 등장한 Supabase가 개발자 커뮤니티에서 점점 더 큰 주목을 받기 시작했습니다.
“Firebase 대안” 을 자처하며 등장한 Supabase는, 이제 단순한 대안이 아니라 독자적인 생태계를 갖춘 프로덕션급 플랫폼으로 성장했습니다. 이 글에서는 Supabase가 무엇인지, Firebase와 어떻게 다른지, 그리고 어떤 상황에서 Supabase를 선택해야 하는지 꼼꼼하게 살펴봅니다.
Supabase란?
Supabase는 오픈소스 Firebase 대안을 표방하는 Backend as a Service 플랫폼입니다. 핵심은 PostgreSQL입니다. Supabase는 Postgres를 중심으로, 개발자가 백엔드를 구성하는 데 필요한 모든 것을 하나의 플랫폼에서 제공합니다.
공식 슬로건처럼 “The Postgres development platform” — Supabase는 Postgres를 기반으로 웹, 모바일, AI 애플리케이션을 구축하기 위한 플랫폼입니다.
Supabase가 제공하는 핵심 기능을 한눈에 보면:
| 기능 | 설명 |
|---|---|
| Database | 전용 PostgreSQL 데이터베이스 |
| Auth | 이메일, 소셜 로그인, SSO, MFA 등 |
| REST / GraphQL API | DB 테이블 기반 자동 API 생성 |
| Realtime | WebSocket 기반 실시간 데이터 구독 |
| Storage | S3 호환 파일/이미지 스토리지 |
| Edge Functions | Deno 기반 서버리스 함수 |
| Vector / AI | pgvector 확장, Vector Buckets |
| Cron & Queues | 백그라운드 작업 자동화 |
이 모든 기능이 하나의 프로젝트 대시보드에서 관리됩니다.
Firebase란?
Firebase는 Google이 운영하는 완전 관리형 BaaS 플랫폼입니다. 2011년 실시간 데이터베이스로 시작해 현재는 인증, 스토리지, 서버리스 함수, 분석, 푸시 알림 등 광범위한 서비스를 제공합니다.
Firebase의 핵심 데이터베이스는 Cloud Firestore로, JSON 도큐먼트 형태로 데이터를 저장하는 NoSQL 데이터베이스입니다. 실시간 동기화가 DNA에 새겨진 플랫폼답게, 모바일 앱 특히 Android/iOS 개발에 최적화되어 있습니다.
가장 큰 차이: SQL vs NoSQL
Supabase와 Firebase의 근본적인 차이는 데이터베이스 패러다임에서 시작됩니다.
Firebase (NoSQL — Firestore)
// Firestore 도큐먼트 예시
{
"users": {
"user_abc123": {
"name": "김철수",
"email": "kim@example.com",
"orders": ["order_1", "order_2"]
}
}
}
- 스키마가 없어서 초기 프로토타이핑이 빠릅니다.
- 컬렉션/도큐먼트 구조로 데이터를 저장합니다.
- 복잡한 조인 쿼리가 어렵고, 관계형 데이터를 표현하려면 데이터를 중복 저장(비정규화)해야 합니다.
- 쿼리 제약이 있어 복잡한 필터링은 클라이언트에서 처리해야 하는 경우가 많습니다.
Supabase (SQL — PostgreSQL)
-- Supabase PostgreSQL 예시
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
total NUMERIC,
created_at TIMESTAMPTZ DEFAULT NOW()
);
- 외래 키, 인덱스, 트랜잭션을 기본으로 지원합니다.
- 복잡한 JOIN, 집계 함수, 서브쿼리 모두 SQL로 처리합니다.
- 스키마를 미리 정의하기 때문에 데이터 무결성이 보장됩니다.
- 어떤 백엔드 개발자든 SQL을 알면 즉시 익힐 수 있습니다.
기능별 상세 비교
1. 데이터베이스
| 항목 | Supabase | Firebase |
|---|---|---|
| 데이터 모델 | 관계형 (PostgreSQL) | 도큐먼트 (NoSQL) |
| 쿼리 언어 | SQL | Firestore 전용 쿼리 |
| 복잡한 JOIN | ✅ 완벽 지원 | ❌ 미지원 |
| 트랜잭션 | ✅ ACID 보장 | ⚠️ 제한적 |
| 스키마 | 명시적 정의 | 스키마리스 |
| 오프라인 지원 | ⚠️ 제한적 | ✅ 우수 |
2. 인증 (Auth)
두 플랫폼 모두 이메일/비밀번호, 소셜 로그인(Google, GitHub 등), 전화/SMS 인증, MFA를 지원합니다. 차이점은 보안 모델에 있습니다.
- Firebase: JavaScript 유사 문법의 Security Rules로 접근 제어
- Supabase: PostgreSQL Row Level Security(RLS)로 DB 레벨에서 접근 제어. SQL을 안다면 훨씬 강력하고 직관적입니다.
3. 실시간 (Realtime)
- Firebase: 실시간이 DNA. 별도 설정 없이 즉각적인 동기화
- Supabase: PostgreSQL Replication Log를 WebSocket으로 변환. 테이블을 직접 구독하는 방식으로, 약간의 설정이 필요하지만 SQL 기반이라 제어가 용이함
4. 가격 정책
Firebase는 읽기/쓰기 횟수 기반 과금이라, 잘못된 쿼리 하나가 예상치 못한 청구서를 만들 수 있습니다. 반면 Supabase는 스토리지 크기 + 사용량 기반으로, 훨씬 예측 가능합니다.
| 플랜 | Supabase | Firebase |
|---|---|---|
| 무료 | 500MB DB, 5GB 스토리지 | Spark 플랜 (제한 있음) |
| 유료 시작 | $25/월 (Pro) | 사용량 기반 (Blaze) |
| 과금 방식 | 예측 가능한 정액+초과 | 읽기/쓰기당 과금 |
5. 오픈소스 & 벤더 락인
이것이 많은 개발자가 Supabase로 이동하는 핵심 이유 중 하나입니다.
- Firebase: 완전 프로프라이어터리. Google 생태계에 종속됩니다. (Google이 서비스를 종료한 전례가 있다는 점을 기억하세요.)
- Supabase: 100% 오픈소스. Docker로 셀프 호스팅이 가능합니다. 언제든지 AWS, DigitalOcean, 또는 자체 서버로 이전할 수 있습니다.
Next.js에서 Supabase 시작하기
이론은 충분합니다. 코드로 확인해봅시다. Next.js App Router + TypeScript 환경에서 Supabase를 세팅하는 방법을 살펴봅니다.
1. 설치
npx create-next-app@latest my-app --typescript --app
cd my-app
npm install @supabase/supabase-js @supabase/ssr
2. 환경 변수 설정
Supabase 대시보드 → Project Settings → API에서 URL과 키를 확인합니다.
# .env.local
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
3. Supabase 클라이언트 생성
App Router 환경에서는 Server Component용과 Client Component용 클라이언트를 분리해서 만들어야 합니다.
// lib/supabase/client.ts — 클라이언트 컴포넌트용
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}
// lib/supabase/server.ts — 서버 컴포넌트용
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
} catch {
// Server Component에서 호출 시 무시
}
},
},
}
)
}
4. 미들웨어 설정
세션을 자동으로 갱신하려면 middleware.ts가 필요합니다.
// middleware.ts
import { createServerClient } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'
export async function middleware(request: NextRequest) {
let supabaseResponse = NextResponse.next({ request })
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value }) =>
request.cookies.set(name, value)
)
supabaseResponse = NextResponse.next({ request })
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
},
},
}
)
// 세션 갱신 (중요: 이 줄을 반드시 포함해야 합니다)
await supabase.auth.getUser()
return supabaseResponse
}
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
],
}
5. 데이터 조회 예시 (Server Component)
// app/page.tsx
import { createClient } from '@/lib/supabase/server'
export default async function HomePage() {
const supabase = await createClient()
const { data: posts, error } = await supabase
.from('posts')
.select('id, title, created_at')
.order('created_at', { ascending: false })
.limit(10)
if (error) {
console.error(error)
return <div>데이터를 불러오지 못했습니다.</div>
}
return (
<main>
<h1>최신 포스트</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</main>
)
}
Server Component에서 await으로 서버사이드 데이터 패칭이 이렇게 간단합니다.
언제 Supabase를 선택해야 할까?
✅ Supabase가 맞는 경우
- 관계형 데이터 구조가 필요한 서비스 (e커머스, SaaS, 대시보드 등)
- SQL을 잘 아는 팀, 또는 SQL을 배우고자 하는 팀
- 오픈소스, 셀프 호스팅, 벤더 락인 회피가 중요한 경우
- AI 기능(벡터 검색, 임베딩)을 DB와 통합하고 싶은 경우
- Next.js, React 등 웹 프레임워크 기반 개발
- 예측 가능한 인프라 비용이 중요한 스타트업
✅ Firebase가 맞는 경우
- Android/iOS 네이티브 앱 개발 (특히 Flutter)
- 실시간 동기화가 핵심인 채팅, 게임, 스코어보드
- 푸시 알림(FCM)이 필수인 앱
- Google 생태계(Analytics, AdMob, Crashlytics)와 깊은 통합이 필요한 경우
- 스키마 없이 빠르게 프로토타이핑하고 싶은 경우
마치며
Supabase는 더 이상 “Firebase 대안” 수준에 머물지 않습니다. PostgreSQL의 강력함을 그대로 활용하면서, BaaS의 편의성을 누릴 수 있는 성숙한 플랫폼으로 성장했습니다.
특히 Next.js + TypeScript 조합으로 웹 서비스를 개발하는 개발자라면, Supabase는 현재 가장 강력한 백엔드 선택지 중 하나입니다. SQL의 표현력, 오픈소스의 자유로움, 그리고 날로 확장되는 AI 기능까지 — 이 시리즈를 통해 Supabase의 모든 것을 하나씩 파헤쳐 보겠습니다.
다음 편에서는 Supabase의 핵심인 PostgreSQL 데이터베이스와 자동 생성 API(REST/GraphQL) 를 Next.js에서 실전으로 다뤄봅니다.