새소식

300x250
AI/Database for AI

[Supabase 시작하기] - 회원 가입부터 기초 CRUD, RAG를 위한 pgvector 활성화 하기

  • -
728x90

안녕하세요! 갓대희 입니다. :- )
오늘은 요즘 개발자들 사이에서 핫한 Supabase에 대해 알아보려고 한다.

 

지난 몇 년간 Firebase에 익숙해져서 새로운 BaaS를 시도하는 게 부담스러웠는데, 최근 AI관련 실습을 이것 저것 하면서 벡터 DB가 필요해졌다.

Pinecone이나 Weaviate 같은 전용 벡터 DB를 따로 쓰자니 복잡하고, Firebase는 NoSQL이라 관계형 데이터 처리가 답답했다. 그러던 중 "PostgreSQL + 벡터 DB를 한 번에?"라는 Supabase의 매력에 빠져버렸다.

 

NoSQL이 대세였던 시대에 다시 PostgreSQL로 회귀하는 트렌드가 흥미롭다. 특히 AI 시대에 들어서면서 복잡한 관계형 데이터와 벡터 임베딩을 함께 다뤄야 하는 상황이 많아졌는데, Supabase의 pgvector 지원이 정말 적절한 타이밍이 아닐까?

기존 Firebase 워크플로우를 완전히 바꿀 필요 없이, PostgreSQL의 강력함과 AI 기능을 동시에 얻을 수 있다는 게 핵심이다. 게다가 오픈소스라 벤더 락인 걱정도 없고.

그래서 이번 글에서는 Supabase 를 그냥 회원가입만 해놓고 이후에 활용해 보자 라는 정도의 컨셉에서 가볍게 글을 작성해보려 한다. 

 

 

🚀 Firebase 대신 Supabase로 갈아타보기
PostgreSQL 기반의 오픈소스 BaaS 플랫폼인 Supabase를 실제로 써보면서 겪은 회원가입부터 RAG 시스템 구축을 위한 database 설정 까지의 내용을 기록 하려고 한다.

AI관련되어서도 supabase가 필요하지만, 개인 프로젝트를 진행하면서 내가 사용하고 있던 "Firebase의 오픈소스 대안"이라고 불리는 Supabase를 알게 되었고, 실제로 써보니 괜찮은 것 같아 결국 supabase에 대해 나도 포스팅을 한개 남겨보려고 한다.

특히 PostgreSQL을 그대로 쓸 수 있고, pgvector로 RAG 시스템까지 구축할 수 있다는 점이 가장 큰 장점이었다.

 

나의 경우 vector store를 chat gpt를 통해 실습 하려다 뭔가 부담이 되어 찾다 보니 Supabase를 사용해볼 수 밖에 없었다. 

ex) open ai vector store

 

Supabase란 무엇인가? 

Supabase는 오픈소스 기반의 BaaS(Backend as a Service) 플랫폼 이다.

간단히 말해, 복잡한 서버 인프라 구축 없이도 데이터베이스(PostgreSQL), 사용자 인증(Authentication), 실시간 데이터(Realtime), 스토리지(Storage), 엣지 함수(Edge Functions) 등 웹/모바일 애플리케이션에 필요한 모든 백엔드 기능을 제공해 준다.

 

Supabase는 Firebase의 오픈소스 대안으로 만들어진 Backend-as-a-Service(BaaS) 플랫폼 이라고 볼 수도 있는데, Firebase와 가장 큰 차이점이 NoSQL 기반이 아닌 PostgreSQL을 사용한다는 점이다.

PostgreSQL을 기반으로 한다는 점에서 SQL에 익숙한 개발자들에게 큰 장점으로 다가올 것 같다.

 

Step1 : Supabase 회원가입하기

회원가입 단계별 과정

  1. supabase.com 접속 후 우측 상단의 Sign In 또는 Start your project 버튼 클릭
  2. 이메일과 비밀번호 입력 또는 GitHub/Google 소셜 로그인 선택 (난 GitHub 으로 진행)
  3. 이메일 인증: 받은 메일에서 "Confirm Your Signup" 링크 클릭 (10분 내 완료 필요)
  4. 인증 완료 후 조직 설정 및 프로젝트 설정 / Region은 한국으로 선택하여 진행 
     - Organization 선택: 개인 계정이면 자동으로 생성된 조직 선택
  5. 인증 완료 후 자동으로 Supabase 대시보드로 이동
💡 팁! 
GitHub 계정으로 가입하면 나중에 프로젝트와 연동할 때 편리하다.
특히 Edge Functions나 GitHub Actions를 쓸 계획이라면 GitHub 가입을 추천한다.
( 나의 경우 Github Actions를 많이 활용하고자 하기 떄문에 왠만하면 GitHub 연동을 추천 한다. ) 

 

Step2 : API 키 확인 및 저장

API 키 확인하기 

  1. 프로젝트 생성 완료 후 좌측 사이드바에서 Project SettingsAPI 메뉴 클릭
  2. Project URLanon public key 확인.
  3. 이 정보들이 나중에 프론트엔드/백엔드 연결할 시 필요하다.

 

ex) 환경변수 설정 예시

# .env.local
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key

 

💡 개발 팁
anon key는 클라이언트에서 사용하고, service_role key는 서버사이드에서만 사용해야 한다.
service_role key는 절대 클라이언트에 노출되면 안 된다!

 

무료 플랜 vs 유료 플랜

2025년 현재 Supabase 요금제는 Free, Pro($25/월), Team($599/월), Enterprise(문의)로 구성되어 있다.

항목 Free Pro
데이터베이스 크기 500MB 8GB
파일 스토리지 1GB 100GB
월간 활성 사용자 50,000명 100,000명
프로젝트 수 2개 무제한
백업 없음 매일
🤯 주의 사항
무료 플랜으로 프로젝트를 진행하다가 1주일간 접속을 안 했을때 프로젝트가 일시정지 되었다.
다시 활성화하는 데 몇 분 걸렸는데, 실서비스에서는 이런 일이 일어나면 안 되니 주의하자.

 

Step3 : 첫 번째 테이블 만들기

GUI로 테이블 생성

  1. 좌측 사이드바에서 Table Editor 클릭
  2. Create a new table 버튼 클릭
  3. 테이블 이름 : profiles 입력 - Enable Row Level Security (RLS) 체크박스 ON (보안상 중요!)
  4. 필요한 컬럼들 추가 후 Save 클릭
    ( 나의 경우 하기 sql로 생성 할꺼라 실제 생성하진 않았다.  하기 sql 참고 )
-- SQL로 직접 생성 (고급)
CREATE TABLE public.profiles (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
    username VARCHAR(50) UNIQUE NOT NULL,
    full_name TEXT,
    bio TEXT,
    avatar_url TEXT,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

 

 

 - 위 내용만 해보고 일단 넘어 가도 괜찮지만, 혹시 db crud 테스트까지 해볼 분들은 하기 내용 참고.


프로젝트 대시보드 탐험하기

프로젝트가 생성되면 Supabase 대시보드로 이동한다. 

 

  • Table Editor (테이블 편집기): 데이터베이스의 테이블을 시각적으로 생성하고 데이터를 CRUD(Create, Read, Update, Delete) 할 수 있는 곳이다. 초기 데이터 입력이나 간단한 쿼리에 유용하다.
  • Authentication (인증): 사용자 회원가입, 로그인, 비밀번호 재설정 등 인증 관련 설정을 관리한다. OAuth 프로바이더(Google, GitHub 등) 연동도 여기서 가능하다.
  • Storage (스토리지): 이미지, 파일 등 사용자가 업로드하는 파일을 저장하고 관리하는 공간이다.
  • SQL Editor (SQL 편집기): 직접 SQL 쿼리를 작성하여 데이터베이스를 조작할 수 있다. 뷰, 함수, 트리거 등 복잡한 로직을 구현할 때 주로 사용한다.
  • API Docs (API 문서): 생성된 프로젝트의 API 엔드포인트와 사용 예시 코드를 자동으로 생성하여 보여준다. 클라이언트에서 Supabase를 연동할 때 이 문서를 참고하면 된다.

 

기초 데이터 CRUD 실습: 'todos' 테이블 만들기 👨‍💻

이제 실제로 데이터를 다뤄볼 시간입니다. 간단한 할 일(todo) 목록을 저장하는 'todos' 테이블을 만들고 CRUD 작업을 해볼게요.

1. 테이블 생성하기

'Table Editor'로 이동하여 'New Table' 버튼을 클릭합니다.

 todos 테이블 스키마

CREATE TABLE public.todos (
  id uuid DEFAULT gen_random_uuid() NOT NULL,
  created_at timestamp with time zone DEFAULT now() NOT NULL,
  task text NULL,
  is_complete boolean DEFAULT false NOT NULL,
  user_id uuid NULL,
  CONSTRAINT todos_pkey PRIMARY KEY (id)
);
/* 나의 경우 테스트이니 foreign key 생성은 생략 */
ALTER TABLE public.todos ADD CONSTRAINT todos_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE;

위 스키마를 참고하여 테이블을 직접 생성가능 하다.

특히 user_id 컬럼은 auth.users 테이블의 id와 외래 키(Foreign Key)로 연결하여 특정 사용자의 할 일을 관리할 수 있도록 한다. ( 나는 sql Editor로 생성하지만, 한번 정도는 직접 gui로 생성해보자.)

 

2. 데이터 추가 (Create)

'Table Editor'에서 'todos' 테이블을 선택한 후, 'Insert row' 버튼을 클릭하여 데이터를 직접 추가하거나, 아래와 같이 SQL Editor에서 쿼리를 실행할 수 있다.

// 새로운 할 일 추가
INSERT INTO todos (task, user_id)
VALUES ('Supabase 공부하기', '00000000-0000-0000-0000-000000000000'); -- user_id는 실제 사용자 ID로 대체

💡 팁 : user_id는 나중에 인증 기능을 붙일 때 현재 로그인한 사용자의 ID로 자동으로 채워질 것이다. 지금은 임의의 User ID를 넣어주자.

3. 데이터 조회 (Read)

가장 흔하게 사용되는 작업이다. 모든 할 일 목록을 가져오거나, 특정 조건에 맞는 할 일을 조회할 수 있다.

// 모든 할 일 조회
SELECT * FROM todos;
// 완료되지 않은 할 일만 조회
SELECT id, task FROM todos WHERE is_complete = false;


4. 데이터 수정 (Update)

특정 할 일의 상태를 변경하거나 내용을 수정할 때 사용한다.

// 특정 할 일을 완료 처리
UPDATE todos
SET is_complete = true
WHERE id = '특정-todo-uuid';
💀 문제 상황 : 권한 부족 에러 (Row Level Security)
처음 Supabase에서 데이터를 수정하려고 할 때 "permission denied for table todos" 같은 에러를 만날 수 있습니다. 이건 Supabase의 RLS(Row Level Security) 때문이다. 기본적으로 모든 테이블은 생성 시 RLS가 활성화되어 있어, 적절한 정책(Policy)이 없으면 데이터를 조회하거나 수정할 수 없다.
✅ 해결 방법: RLS 정책 추가
'Authentication' 메뉴 아래의 'Policies' 탭에서 'New policy'를 클릭하고, 'Enable Row Level Security'를 비활성화하거나, 혹은 적절한 정책을 추가해야 한다. 개발 초기에는 RLS를 비활성화하여 편하게 개발하고, 프로덕션 배포 전에 보안 정책을 세밀하게 설정하는 것을 추천하기도 한다. 예를 들어, 모든 사용자가 todos를 읽을 수 있도록 허용하는 정책은 다음과 같다.
CREATE POLICY "Allow read access for all users" ON public.todos FOR SELECT USING (true);


5. 데이터 삭제 (Delete)

할 일을 목록에서 제거할 때 사용한다.

// 특정 할 일 삭제
DELETE FROM todos
WHERE id = '삭제할-todo-user-id';

 

 


여기서 부터는 방향을 바꿔

Rag 관련 간단한 테스트를 진행하기 위해 새로운 프로젝트를 추가 하고, 벡터 DB 생성 하는 실습을 해보.

 

Step 6: 두 번째 프로젝트 생성하기

프로젝트 생성 과정

  1. 대시보드에서 New Project 버튼 클릭
  2. Organization 선택 : 개인 계정이면 자동으로 생성된 조직 선택
  3. 프로젝트 이름 입력 (ex> rag project)
  4. 데이터베이스 비밀번호 설정 (대소문자+숫자+특수문자 포함 12자 이상 필수!)
  5. Region 선택 : Seoul
  6. Pricing Plan : Free 선택 (무료로 시작)
  7. Create new project 클릭 후 2-3분 대기

 

Step 7: 벡터 DB로 RAG 시스템 만들기

최근 AI 기술의 발전과 함께 벡터 데이터베이스에 대한 관심이 뜨겁다.

Supabase는 PostgreSQL 기반이기 때문에 pgvector 확장(extension)을 통해 벡터 데이터를 효율적으로 관리하고 유사성 검색을 수행할 수 있다.

이는 RAG(Retrieval Augmented Generation) 시스템이나 추천 시스템 등 다양한 AI 서비스 구축에 필수적인 요소가 다.

pgvector 확장 활성화

  1. Supabase 대시보드에서 DatabaseExtensions 클릭
  2. 검색창에 "vector" 입력
  3. vector 확장의 Enable 버튼 클릭

 - 또는 sql을 통해 활성화 가능하다.

// SQL Editor에서 pgvector 확장 활성화
CREATE EXTENSION IF NOT EXISTS vector;

 

  - node 환경에서 테스트 가능하지만 하기 내용도 지금 세션보다는 별도의 세션에서 진행하는게 좋으니 눈으로만 살펴보자.

 - 하기 내용은 벡터 데이터를 저장할 테이블을 생성해 보는 예시이다. embedding이라는 이름으로 1536차원 벡터를 저장하는 컬럼을 추가한다. (OpenAI의 text-embedding-ada-002 모델이 1536차원 임베딩을 생성다.)

ex) 난 이미 사용하고 있기 떄문에 논문 하나를 ai를 통해 임베딩 시켰다. (혹시 어떤 형식으로 데이터가 들어가는지 궁금할 수 있어 첨부) (content가 실제 내용 / embedding에 들어간 값이 벡터 값 이다.)

-- RAG 시스템용 테이블 및 함수 생성
-- 문서 테이블 생성
CREATE TABLE documents (
    id serial PRIMARY KEY,
    title TEXT NOT NULL,
    content TEXT NOT NULL,
    embedding vector(1536),
    metadata JSONB,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- 유사도 검색 함수
CREATE OR REPLACE FUNCTION match_documents (
    query_embedding vector(1536),
    match_threshold float,
    match_count int
)
RETURNS TABLE (
    id bigint,
    title text,
    content text,
    similarity float
)
LANGUAGE sql STABLE
AS $$
SELECT 
    documents.id,
    documents.title,
    documents.content,
    1 - (documents.embedding <=> query_embedding) as similarity
FROM documents
WHERE 1 - (documents.embedding <=> query_embedding) > match_threshold
ORDER BY documents.embedding <=> query_embedding
LIMIT match_count;
$$;
// OpenAI와 연동한 RAG 시스템 구현
// 1. 패키지 설치
npm install openai

// 2. RAG 시스템 구현
import OpenAI from 'openai'
import { supabase } from './supabase'

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY
})

// 문서를 임베딩으로 변환하여 저장
export async function embedAndStore(title, content) {
  const response = await openai.embeddings.create({
    model: 'text-embedding-3-small',
    input: content
  })
  
  const embedding = response.data[0].embedding
  
  const { data, error } = await supabase
    .from('documents')
    .insert({ title, content, embedding })
    
  if (error) throw error
  return data
}

// 질문에 대한 관련 문서 검색
export async function searchSimilarDocs(query) {
  const response = await openai.embeddings.create({
    model: 'text-embedding-3-small', 
    input: query
  })
  
  const queryEmbedding = response.data[0].embedding
  
  const { data, error } = await supabase
    .rpc('match_documents', {
      query_embedding: queryEmbedding,
      match_threshold: 0.7,
      match_count: 5
    })
    
  return data
}

// RAG로 답변 생성
export async function generateAnswer(question) {
  const docs = await searchSimilarDocs(question)
  const context = docs.map(doc => doc.content).join('\n\n')
  
  const completion = await openai.chat.completions.create({
    model: 'gpt-4',
    messages: [
      {
        role: 'system',
        content: '당신은 제공된 문서를 바탕으로 정확한 답변을 하는 AI입니다.'
      },
      {
        role: 'user',
        content: `문서: ${context}\n\n질문: ${question}`
      }
    ]
  })
  
  return completion.choices[0].message.content
}

실제 사용해보기

  1. 문서 저장: await embedAndStore("Supabase 가이드", "Supabase는 PostgreSQL 기반의...")
  2. 질문하기: const answer = await generateAnswer("Supabase란 무엇인가요?")
  3. 답변 확인.

 

ex) 나의 경우 rag관련 학습자료를 DB로 구축하여 챗봇을 통해 실습 해보았다.
(지금 다룰 내용은 아니지만, 이 벡터 db를 통해 챗봇을 만든다면 다음과같이 봇을 만들 수도 있다.) 

ex) 해당 정보를 통한 질의에 대한 대답은 가능 하도록 처리

ex) 해당 문서의 내용 이외에는 대답 못하게 처리

 

 - 이 두 예시가 내가 supabase를 시작하게 된 실제 목적이다. 감사합니다. 수파베이스 ㅎㅎ 

 

내용 요약

  • PostgreSQL의 장점 : Firebase의 NoSQL과 달리 복잡한 쿼리와 관계형 데이터 처리가 가능하다.
  • 벡터 DB 통합 : pgvector로 별도 벡터 DB 없이 RAG 시스템 구축 가능하다.
  • 무료 플랜의 한계 : 1주일 비활성화 시 프로젝트 일시정지, 2개 프로젝트 제한이 있다.
  • RLS의 중요성 : 처음에는 RLS 때문에 삽질 좀 했지만, 덕분에 보안에 대한 중요성을 다시 한번 깨달았다. 초기 개발 시에는 잠시 비활성화할 수 있지만, 실제 서비스에서는 사용자 권한에 따른 세밀한 RLS 정책 설정이 필수.
  • AI 생태계 연동 : OpenAI, LangChain 등과 쉽게 연동되어 AI 앱 개발이 간편하다.

 

자주 묻는 질문❓

Q: Supabase가 Firebase보다 나은 점은?
A: PostgreSQL 사용으로 복잡한 쿼리 가능, 오픈소스라 벤더 락인 없음, 비용이 더 예측 가능하다.
Q: 벡터 DB 기능으로 어떤 걸 만들 수 있나?
A: RAG 시스템, 의미론적 검색, 추천 시스템, 문서 분류 등 AI 기반 앱을 쉽게 구축할 수 있다. Pinecone 같은 별도 벡터 DB가 필요 없다.
Q: 무료 플랜으로 실서비스가 가능한가?
A: 토이 프로젝트나 MVP 정도는 가능하지만, 백업 기능이 없고 1주일 비활성화 시 일시정지되므로 실서비스엔 Pro 플랜을 추천한다.
Q: 다른 지역(Region) 변경이 가능한가?
A: 프로젝트 생성 후에는 변경 불가능하다. 처음 생성할 때 신중하게 선택해야 한다.

📚 참고 자료

Supabase는 PostgreSQL의 강력함과 Firebase의 편리함을 잘 결합한 플랫폼이다.

특히 관계형 데이터베이스가 필요한 프로젝트나 RAG 시스템 같은 AI 기능을 구현할 때 Firebase보다 훨씬 적합하다.

pgvector를 통한 벡터 DB 기능까지 제공하므로 AI 개발자에게는 정말 매력적인 선택지다.

무료 플랜으로 시작해서 프로젝트가 커지면 Pro 플랜으로 업그레이드하는 전략을 추천한다.

 

300x250
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.

💡 AI 관련 질문이 있나요? 눌러보세요!