Supabase๋ PostgreSQL ๊ธฐ๋ฐ์ ์คํ์์ค BaaS(Backend as a Service) ํ๋ซํผ์ผ๋ก, Firebase์ ๋์์ผ๋ก ์ค๊ณ๋์์ต๋๋ค. ์ธ์ฆ, ๋ฐ์ดํฐ๋ฒ ์ด์ค, ์ค์๊ฐ ์ฒ๋ฆฌ, ํ์ผ ์คํ ๋ฆฌ์ง, ์๋ฒ๋ฆฌ์ค ํจ์๋ฅผ ํ๋์ ํจํค์ง๋ก ์ ๊ณตํ์ฌ ๋ฐฑ์๋ ์ธํ๋ผ ๊ตฌ์ถ ์๊ฐ์ ๋ํญ ๋จ์ถํ ์ ์์ต๋๋ค. ์ด ๊ธ์์๋ Supabase์ ํต์ฌ ๊ฐ๋ ๊ณผ Firebase, Appwrite์์ ์ฐจ์ด์ ์ ์ค๋ฌด ๊ด์ ์์ ๋น๊ตํฉ๋๋ค.
๐งฉ Supabase๋? #
Supabase๋ Google Firebase์ ์คํ์์ค ๋์์ผ๋ก 2020๋ ๋ฑ์ฅํ BaaS(Backend as a Service) ํ๋ซํผ์ ๋๋ค. PostgreSQL์ ํต์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ์ฌ์ฉํ๋ฉฐ, ์ธ์ฆยท์ค์๊ฐ ์ฒ๋ฆฌยทํ์ผ ์คํ ๋ฆฌ์งยท์๋ฒ๋ฆฌ์ค ํจ์๋ฅผ ํตํฉ ์ ๊ณตํฉ๋๋ค.
Firebase๊ฐ NoSQL(Firestore) ๊ธฐ๋ฐ์ธ ๊ฒ๊ณผ ๋ฌ๋ฆฌ, Supabase๋ ํ์ค SQL๊ณผ ๊ด๊ณํ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ์ฌ์ฉํ ์ ์๋ค๋ ์ ์ด ๊ฐ์ฅ ํฐ ์ฐจ๋ณ์ ์ ๋๋ค. ์คํ์์ค์ด๊ธฐ ๋๋ฌธ์ ํด๋ผ์ฐ๋ ํธ์คํ ๋ฟ๋ง ์๋๋ผ ์์ฒด ์๋ฒ์์ ์ ํ ํธ์คํ ๋ ๊ฐ๋ฅํฉ๋๋ค.
๐ BaaS(Backend as a Service)๋? #
BaaS๋ “์ธ์ฆ, ๋ฐ์ดํฐ๋ฒ ์ด์ค, ํ์ผ ์คํ ๋ฆฌ์ง ๋ฑ ๊ณตํต ๋ฐฑ์๋ ๊ธฐ๋ฅ์ ์๋น์ค๋ก ์ ๊ณตํ๋ ํ๋ซํผ"์ ๋๋ค. ๊ฐ๋ฐ์๊ฐ ์ง์ ์๋ฒ๋ฅผ ๊ตฌ์ถํ๊ฑฐ๋ API๋ฅผ ๊ฐ๋ฐํ ํ์ ์์ด, ํ๋ก ํธ์๋ ์ฝ๋๋ง์ผ๋ก ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค ์ ์๊ฒ ํด์ค๋๋ค.
Tip: BaaS๋ ์คํํธ์ ์ด๋ ์๊ท๋ชจ ํ์ด ๋น ๋ฅธ ์์ฅ ์ง์ (MVP)์ด ํ์ํ ๋ ํนํ ํจ๊ณผ์ ์ ๋๋ค.
๋ํ์ ์ธ BaaS ํ๋ซํผ์ผ๋ก๋ Firebase, Supabase, Appwrite๊ฐ ์์ผ๋ฉฐ, ๊ฐ๊ฐ ์ค๊ณ ์ฒ ํ์ด ๋ค๋ฆ ๋๋ค.
โก Firebase vs Supabase vs Appwrite ๋น๊ต #
| ํญ๋ชฉ | Firebase | Supabase | Appwrite |
|---|---|---|---|
| ์ค๊ณ ๋ฐฉํฅ | ์์ ํ ์งํฅ | ํตํฉ ๋ฐ์ดํฐ ํ๋ฆ | ์ ํ ํธ์คํ ์์ ๋ |
| ๋ฐ์ดํฐ๋ฒ ์ด์ค | NoSQL (Firestore) | SQL (PostgreSQL) | SQL/NoSQL ์ ํ |
| ์ ๊ณต ๋ฐฉ์ | ์์ ๊ด๋ฆฌํ | ๊ด๋ฆฌํ + ๋ก์ปฌ ๊ฐ๋ฐ | ์ง์ ์ด์ |
| ์คํ์์ค | โ | โ | โ |
| ๋ฒค๋ ๋ฝ์ธ | ๋์ (Google) | ๋ฎ์ | ์์ |
| ๊ถํ ๊ตฌ์กฐ | ๊ธฐ๋ฅ๋ณ ๋ถ๋ฆฌ | RLS ๊ธฐ๋ฐ ํตํฉ | ์ง์ ๊ตฌ์ฑ |
| AI/๋ฒกํฐ ์ง์ | ๋ณ๋ ์๋ฃจ์ ํ์ | pgvector ๊ธฐ๋ณธ ์ง์ | ๋ณ๋ ์ค์ ํ์ |
| ์ ํฉ ํ | MVP/๋ชจ๋ฐ์ผ ํ | ํ๋ก ํธ ์ค์ฌ ์๊ท๋ชจ ํ | ์ธํ๋ผ ์ด์ ๊ฐ๋ฅ ํ |
Firebase๊ฐ ์ ํฉํ ๊ฒฝ์ฐ #
Firebase๋ “๋ชจ๋ฐ์ผ ์ฑ ๊ฐ๋ฐ๊ณผ ์ด๊ณ ์ MVP ๊ตฌํ"์ ์ต์ ํ๋ ํ๋ซํผ์ ๋๋ค. Google ์ํ๊ณ์์ ๊ธด๋ฐํ ํตํฉ, ์ค์๊ฐ ๋ฐ์ดํฐ ๋๊ธฐํ, Firebase Analytics ๋ฑ ๋ชจ๋ฐ์ผ์ ํนํ๋ ์๋น์ค๊ฐ ๊ฐ์ ์ ๋๋ค.
- ๋ชจ๋ฐ์ผ(iOS/Android) ์ฑ ๊ฐ๋ฐ ์ค์ฌ
- Google ์ํ๊ณ ์ ๋ฐ ํ์ฉ์ด ํ์ํ ๊ฒฝ์ฐ
- NoSQL ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ์ต์ํ ํ
Supabase๊ฐ ์ ํฉํ ๊ฒฝ์ฐ #
Supabase๋ “SQL์ ์ต์ํ ํ์ด ๋น ๋ฅธ ๊ฐ๋ฐ๊ณผ ํต์ ๊ถ์ ๋์์ ์ํ ๋” ์ต์ ์ ๋๋ค. ์ฅ๊ธฐ ์ด์์ ๊ณ ๋ คํ๋ฉด์๋ ๋น ๋ฅด๊ฒ ์ ํ์ ์ถ์ํด์ผ ํ๋ ํ์ ์ด์ธ๋ฆฝ๋๋ค.
- SQL ๋ฐ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ต์ํ ํ
- AI/ML ๊ธฐ๋ฅ์ ์ฑ์ ํตํฉํ ๊ณํ์ด ์๋ ๊ฒฝ์ฐ
- Firebase์ ๋ฒค๋ ๋ฝ์ธ์ ํผํ๊ณ ์ถ์ ๊ฒฝ์ฐ
Appwrite๊ฐ ์ ํฉํ ๊ฒฝ์ฐ #
Appwrite๋ “์ธํ๋ผ๋ฅผ ์ง์ ์ด์ํ ์ ์๋ ํ์ด ์์ ํ ๋ฐ์ดํฐ ์ฃผ๊ถ์ ์ํ ๋” ์ ํฉํฉ๋๋ค. ์ ํ ํธ์คํ ์ ํตํด ๋ฐ์ดํฐ๋ฅผ ์์ ํ ํต์ ํ ์ ์์ต๋๋ค.
- ๋ฐ์ดํฐ๋ฅผ ์์ฒด ์๋ฒ์์ ์์ ํ ํต์ ํด์ผ ํ๋ ๊ฒฝ์ฐ
- ์ธํ๋ผ ์ด์ ์ญ๋์ด ์๋ ํ
- ์คํ์์ค ์ปค์คํฐ๋ง์ด์ง์ด ํ์ํ ๊ฒฝ์ฐ
๐ ๏ธ Supabase ํต์ฌ ๊ธฐ๋ฅ #
1๏ธโฃ Database (PostgreSQL) #
Supabase์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ์์ ํ PostgreSQL์ ๋๋ค. ๋ณต์กํ SQL ์ฟผ๋ฆฌ, ์กฐ์ธ, ํธ๋์ญ์ , ์ธ๋ฑ์ค๋ฅผ ๋ชจ๋ ํ์ฉํ ์ ์์ผ๋ฉฐ, Row Level Security(RLS)๋ก ์ฌ์ฉ์๋ณ ๋ฐ์ดํฐ ์ ๊ทผ ๊ถํ์ DB ๋ ๋ฒจ์์ ์ ์ดํฉ๋๋ค.
1-- RLS ์ ์ฑ
์์: ์ฌ์ฉ์๊ฐ ์์ ์ ๋ฐ์ดํฐ๋ง ์กฐํ
2CREATE POLICY "users can view own data"
3ON profiles
4FOR SELECT
5USING (auth.uid() = user_id);Tip: RLS๋ฅผ ํ์ฑํํ๋ฉด API์์ ๋ณ๋ ๊ถํ ์ฒดํฌ ์์ด DB ์์ฒด์์ ๋ณด์์ด ์ฒ๋ฆฌ๋ฉ๋๋ค.
2๏ธโฃ Auth (์ธ์ฆ) #
Supabase Auth๋ ์ด๋ฉ์ผ/ํจ์ค์๋, ์์ ๋ก๊ทธ์ธ(Google, GitHub, Apple), OTP, ํจ์คํค๋ฅผ ๋์๋ณด๋์์ ํด๋ฆญ ๋ช ๋ฒ์ผ๋ก ์ค์ ํ ์ ์์ต๋๋ค. JWT ๊ธฐ๋ฐ์ ํ ํฐ๊ณผ ์ธ์ ๊ด๋ฆฌ๋ ์๋์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
1import { createClient } from '@supabase/supabase-js'
2
3const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY)
4
5// ์์
๋ก๊ทธ์ธ (GitHub)
6const { data, error } = await supabase.auth.signInWithOAuth({
7 provider: 'github'
8})
9
10// ์ด๋ฉ์ผ ๋ก๊ทธ์ธ
11const { data, error } = await supabase.auth.signInWithPassword({
12 email: 'user@example.com',
13 password: 'password'
14})3๏ธโฃ Realtime (์ค์๊ฐ ์ฒ๋ฆฌ) #
Supabase Realtime์ PostgreSQL์ ๋ณ๊ฒฝ ์ฌํญ์ ์น์์ผ์ผ๋ก ํด๋ผ์ด์ธํธ์ ์ฆ์ ์ ๋ฌํฉ๋๋ค. ๋ณ๋ ํด๋ง ์์ด ์ฑํ , ์๋ฆผ, ํ์ ๋๊ตฌ๋ฅผ ๊ตฌํํ ์ ์์ต๋๋ค.
1// ์ค์๊ฐ ๋ฉ์์ง ๊ตฌ๋
2const channel = supabase
3 .channel('messages')
4 .on(
5 'postgres_changes',
6 { event: 'INSERT', schema: 'public', table: 'messages' },
7 (payload) => {
8 console.log('์ ๋ฉ์์ง:', payload.new)
9 }
10 )
11 .subscribe()4๏ธโฃ Storage (ํ์ผ ๊ด๋ฆฌ) #
์ด๋ฏธ์งยท๋์์ ์ ๋ก๋ ์ ์๋ ์ธ๋ค์ผ ๋ณํ, CDN ์ฐ๋, RLS ๊ธฐ๋ฐ ์ ๊ทผ ์ ์ด๊ฐ ๊ธฐ๋ณธ ๋ด์ฅ๋์ด ์์ต๋๋ค.
1// ํ์ผ ์
๋ก๋
2const { data, error } = await supabase.storage
3 .from('avatars')
4 .upload(`${userId}/avatar.png`, file)
5
6// ํผ๋ธ๋ฆญ URL ์กฐํ
7const { data } = supabase.storage
8 .from('avatars')
9 .getPublicUrl(`${userId}/avatar.png`)5๏ธโฃ Edge Functions (์๋ฒ๋ฆฌ์ค) #
Deno ๊ธฐ๋ฐ์ ์๋ฒ๋ฆฌ์ค ํจ์๋ก ์ธ์ฆ ์ฒดํฌ, ์นํ ์ฒ๋ฆฌ, ์ธ๋ถ API ํธ์ถ, AI ์ฐ๋ ๋ฑ ์๋ฒ ๋ก์ง์ ๋น ๋ฅด๊ฒ ๋ฐฐํฌํ ์ ์์ต๋๋ค.
1// Edge Function ์์: OpenAI ์ฐ๋
2import { serve } from 'https://deno.land/std@0.177.0/http/server.ts'
3
4serve(async (req) => {
5 const { query } = await req.json()
6
7 const response = await fetch('https://api.openai.com/v1/chat/completions', {
8 method: 'POST',
9 headers: {
10 'Authorization': `Bearer ${Deno.env.get('OPENAI_API_KEY')}`,
11 'Content-Type': 'application/json'
12 },
13 body: JSON.stringify({
14 model: 'gpt-4o',
15 messages: [{ role: 'user', content: query }]
16 })
17 })
18
19 return new Response(await response.text(), {
20 headers: { 'Content-Type': 'application/json' }
21 })
22})6๏ธโฃ Vector DB (pgvector) #
Supabase๋ pgvector ํ์ฅ์ ๊ธฐ๋ณธ ์ง์ํ์ฌ ๋ณ๋ ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ด PostgreSQL ์์์ AI ์๋ฒ ๋ฉ ์ ์ฅ๊ณผ ์ ์ฌ๋ ๊ฒ์์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
1-- pgvector ํ์ฅ ํ์ฑํ
2CREATE EXTENSION IF NOT EXISTS vector;
3
4-- ์๋ฒ ๋ฉ ์ปฌ๋ผ์ด ์๋ ํ
์ด๋ธ ์์ฑ
5CREATE TABLE documents (
6 id BIGSERIAL PRIMARY KEY,
7 content TEXT,
8 embedding VECTOR(1536)
9);
10
11-- ์ฝ์ฌ์ธ ์ ์ฌ๋ ๊ฒ์
12SELECT content, 1 - (embedding <=> query_embedding) AS similarity
13FROM documents
14ORDER BY embedding <=> query_embedding
15LIMIT 5;Tip: Supabase + pgvector ์กฐํฉ์ RAG(Retrieval-Augmented Generation) ์์คํ ๊ตฌ์ถ์ ๋งค์ฐ ํจ๊ณผ์ ์ ๋๋ค.
๐ฐ ์๊ธ์ ๋น๊ต #
| ํ๋ | ๊ฐ๊ฒฉ | DB ์ฉ๋ | ์คํ ๋ฆฌ์ง | MAU | ํน์ด์ฌํญ |
|---|---|---|---|---|---|
| Free | ๋ฌด๋ฃ | 500MB | 1GB | 10,000 | 1์ฃผ ๋ฏธ์ฌ์ฉ ์ ์๋ ์ค์ง, 2๊ฐ ํ๋ก์ ํธ ์ ํ |
| Pro | $25/์ | 8GB | 100GB | 100,000 | ์๋ ๋ฐฑ์ , ์ปค์คํ ๋๋ฉ์ธ |
| Team | $599/์ | ์ปค์คํ | ์ปค์คํ | ๋ฌด์ ํ | SOC2, HIPAA, SSO ์ง์ |
| Enterprise | ๋ฌธ์ | ์ปค์คํ | ์ปค์คํ | ๋ฌด์ ํ | ์ ์ฉ ์๋ฒ, SLA ๋ณด์ฅ |
โ ๏ธ Free ํ๋์ 7์ผ ๋์ ํ๋์ด ์์ผ๋ฉด ํ๋ก์ ํธ๊ฐ ์๋ ์ผ์์ ์ง๋ฉ๋๋ค. ๊ฐ์ธ ํ๋ก์ ํธ๋ ํ ์คํธ ํ๊ฒฝ์์ ์ฃผ์๊ฐ ํ์ํฉ๋๋ค.
โ Supabase ์ฅ๋จ์ ์์ฝ #
์ฅ์ #
- SQL ํ์ค ์ง์: ๋ณต์กํ ๊ด๊ณํ ์ฟผ๋ฆฌ, ์กฐ์ธ, ํธ๋์ญ์ ์์ ์ง์
- ์คํ์์ค: ๋ฒค๋ ๋ฝ์ธ ์์ด ์์ฒด ํธ์คํ ์ผ๋ก ์ ํ ๊ฐ๋ฅ
- AI ํตํฉ ์ฉ์ด: pgvector๋ก ๋ฒกํฐ DB๋ฅผ ๋ณ๋ ์๋น์ค ์์ด ํ์ฉ
- ํตํฉ ์๋ฃจ์ : ์ธ์ฆยทDBยท์คํ ๋ฆฌ์งยท์ค์๊ฐยทํจ์๊ฐ ํ๋์ ํจํค์ง
- ๋น์ฉ ์์ธก ๊ฐ๋ฅ: Firebase์ ์ฌ์ฉ๋ ๊ธฐ๋ฐ ๊ณผ๊ธ๊ณผ ๋ฌ๋ฆฌ ํ๋ ๊ธฐ๋ฐ ์ ์ก์
๋จ์ #
- Free ํ๋ ์ ์ฝ: 1์ฃผ ๋ฏธ์ฌ์ฉ ์ ์๋ ์ผ์์ ์ง, 2๊ฐ ํ๋ก์ ํธ ์ ํ
- Region ๊ณ ์ : ํ๋ก์ ํธ ์์ฑ ํ ๋ฆฌ์ ๋ณ๊ฒฝ ๋ถ๊ฐ
- PostgreSQL ๊ธฐ๋ณธ ์ง์ ํ์: SQL์ ์ต์ํ์ง ์์ผ๋ฉด ์ด๊ธฐ ์ค์ ์ด ์ด๋ ค์ธ ์ ์์
- Firebase ๋ง์ด๊ทธ๋ ์ด์ ๋ณต์ก๋: NoSQL โ ๊ด๊ณํ ์ ํ ์ ๋ฐ์ดํฐ ์ฌ์ค๊ณ ํ์
๐ ๋น ๋ฅธ ์์ ๊ฐ์ด๋ #
Supabase CLI ์ค์น ๋ฐ ๋ก์ปฌ ๊ฐ๋ฐ ํ๊ฒฝ ๊ตฌ์ฑ #
1# Supabase CLI ์ค์น
2npm install -g supabase
3
4# ๋ก๊ทธ์ธ
5supabase login
6
7# ์ ํ๋ก์ ํธ ์ด๊ธฐํ
8supabase init
9
10# ๋ก์ปฌ ๊ฐ๋ฐ ์๋ฒ ์์ (Docker ํ์)
11supabase startNext.js + Supabase ์ฐ๋ #
1npm install @supabase/supabase-js @supabase/ssr1// lib/supabase.ts
2import { createBrowserClient } from '@supabase/ssr'
3
4export const supabase = createBrowserClient(
5 process.env.NEXT_PUBLIC_SUPABASE_URL!,
6 process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
7)1// ๋ฐ์ดํฐ ์กฐํ ์์
2const { data: posts, error } = await supabase
3 .from('posts')
4 .select('id, title, created_at')
5 .order('created_at', { ascending: false })
6 .limit(10)โ ์์ฃผ ๋ฌป๋ ์ง๋ฌธ #
Q. Supabase์ Firebase ์ค ๋ฌด์์ ์ ํํด์ผ ํ๋์? #
SQL๊ณผ ๊ด๊ณํ ๋ฐ์ดํฐ์ ์ต์ํ๊ฑฐ๋ AI ๊ธฐ๋ฅ ํตํฉ์ด ํ์ํ๋ค๋ฉด Supabase๋ฅผ ๊ถ์ฅํฉ๋๋ค. ๋ชจ๋ฐ์ผ ์ฑ ๊ฐ๋ฐ์ด ์ฃผ๋ชฉ์ ์ด๊ณ Google ์ํ๊ณ๋ฅผ ์ ๊ทน ํ์ฉํ๋ค๋ฉด Firebase๊ฐ ๋ ์ ํฉํฉ๋๋ค.
Q. Supabase๋ ์ ํ ํธ์คํ ์ด ๊ฐ๋ฅํ๊ฐ์? #
๋ค, ๊ฐ๋ฅํฉ๋๋ค. Supabase๋ ์คํ์์ค์ด๋ฉฐ Docker Compose๋ก ์์ฒด ์๋ฒ์ ๋ฐฐํฌํ ์ ์์ต๋๋ค. supabase/supabase GitHub ๋ฆฌํฌ์งํ ๋ฆฌ์์ ๊ณต์ ์
ํ ํธ์คํ
๊ฐ์ด๋๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
Q. Free ํ๋์ ํ๋ก์ ํธ ์๋ ์ค์ง๋ฅผ ๋ฐฉ์งํ ์ ์๋์? #
๋ฌด๋ฃ ํ๋์์๋ 7์ผ ์ฐ์ ๋ฏธ์ฌ์ฉ ์ ์๋ ์ผ์์ ์ง๋ฉ๋๋ค. ์ฃผ๊ธฐ์ ์ผ๋ก ์ ์ํ๊ฑฐ๋, Pro ํ๋($25/์)์ผ๋ก ์ ๊ทธ๋ ์ด๋ํ๋ฉด ์ด ์ ํ์ด ์ฌ๋ผ์ง๋๋ค.
Q. pgvector๋ฅผ ํ์ฉํ AI ๊ธฐ๋ฅ์ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์? #
Supabase ๋์๋ณด๋์ Database > Extensions ํญ์์ vector ํ์ฅ์ ํ์ฑํํฉ๋๋ค. ์ดํ VECTOR ํ์
์ปฌ๋ผ์ ๊ฐ์ง ํ
์ด๋ธ์ ์์ฑํ๊ณ OpenAI ๋ฑ ์๋ฒ ๋ฉ ๋ชจ๋ธ๋ก ์์ฑํ ๋ฒกํฐ๋ฅผ ์ ์ฅํ๋ฉด ์ ์ฌ๋ ๊ฒ์์ด ๊ฐ๋ฅํฉ๋๋ค.
Q. Free ํ๋์ ํ๋ก์ ํธ ๊ฐ์ ์ ํ์? #
Free ํ๋์์๋ ์ต๋ 2๊ฐ์ ํ๋ก์ ํธ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. Pro ํ๋๋ถํฐ๋ ์ ํ์ด ์์ต๋๋ค.