Supabase Client vs 쿼리 빌더: 비슷해 보이지만 완전히 다른 두 세계
1. 문제의 배경
처음 Supabase를 접하면 다음과 같은 코드를 작성하게 됩니다.
const { data, error } = await supabase
.from('posts')
.select('*')
.eq('status', 'published')
.order('created_at', { ascending: false });
이 코드는 Knex나 Prisma의 쿼리 빌더와 매우 유사해 보입니다. 그래서 많은 개발자들이 "Supabase Client는 그냥 자바스크립트로 SQL을 짜게 해주는 도구구나"라고 생각하곤 합니다. 하지만 이 둘은 통신 프로토콜부터 보안 모델까지 모든 것이 다릅니다.
2. 작동 원리의 차이: HTTP vs TCP
가장 큰 차이는 "누가 SQL을 만드는가"와 "데이터를 어떻게 전달하는가"에 있습니다.
1) 전통적인 쿼리 빌더 (Knex, Kysely, Prisma 등)
- 과정: JS 코드 → 라이브러리가 SQL 문자열 생성 → DB 연결(TCP/IP)을 통해 직접 전송.
- 특징: 어플리케이션 서버가 DB의 전권을 쥐고 있습니다. SQL의 모든 기능을 사용할 수 있으며, 데이터베이스와 상시 연결된 Connection Pool을 관리합니다.
2) Supabase Client
- 과정: JS 코드 → URL 파라미터와 HTTP 헤더로 변환 → PostgREST(API 서버)로 전송 → PostgREST가 SQL로 변환하여 실행.
- 특징: DB 앞에 'API 서버'가 하나 더 있는 구조입니다. 클라이언트는 DB와 직접 통신하는 것이 아니라, 잘 설계된 REST API를 호출하는 것입니다.
3. 보안 모델의 혁신: RLS (Row Level Security)
전통적인 쿼리 빌더는 보통 "Admin 권한"으로 DB에 접근합니다. 즉, 서비스 로직에서 where user_id = current_user 같은 조건을 실수로 빼먹으면 전체 데이터가 유출되는 보안 사고가 터질 수 있습니다.
하지만 Supabase Client는 RLS(Row Level Security)를 기반으로 합니다.
- 클라이언트가 요청을 보낼 때 사용자의 JWT(인증 토큰)가 함께 전달됩니다.
- DB 엔진 레벨에서 "이 토큰을 가진 사용자가 이 행(Row)을 볼 권한이 있는가?"를 직접 판단합니다.
- 시니어의 시각: 이는 보안의 책임을 애플리케이션 코드(App Logic)에서 데이터베이스 엔진(Database Layer)으로 옮긴 아키텍처적 전환입니다. 코드 기반 보안보다 훨씬 강력하고 안전합니다.
4. 한계와 트러블슈팅: 언제 RPC를 써야 할까?
Supabase Client가 제공하는 메서드 체이닝은 편리하지만, 복잡한 비즈니스 로직에서는 한계가 발생합니다.
- 복잡한 Join과 서브쿼리: PostgREST는 표준적인 Join은 훌륭하게 처리하지만, 3개 이상의 테이블이 얽힌 복잡한 Join이나 윈도우 함수(Window Function) 등을 체이닝으로 표현하기는 매우 까다롭습니다.
- 원자적 트랜잭션: 클라이언트 측에서 여러 번의
.from().update()를 호출하는 것은 각각 독립적인 HTTP 요청입니다. 네트워크 장애가 발생하면 데이터 정합성이 깨질 수 있습니다.
- 해결책 (Stored Procedures): 이런 경우 전문가들은 RPC(Remote Procedure Call)를 사용합니다. DB 내부에 SQL 함수를 미리 정의해두고 클라이언트에서는 이름만 호출하는 방식입니다.
// 💡 복잡한 트랜잭션이나 로직은 RPC로 해결
const { data, error } = await supabase.rpc('process_order_and_inventory', {
order_id: 123
});
5. 결과 및 Trade-off
동작 방식의 차이로 인해 다음과 같은 장단점이 명확해집니다.
- Supabase Client: 백엔드 코드 없이 프론트엔드에서 직접 DB를 다룰 수 있어 생산성이 극대화됩니다. 하지만 복잡한 SQL 기능을 100% 활용하기 어렵고 HTTP 오버헤드가 존재합니다.
- 전통적 쿼리 빌더: SQL의 모든 강력한 기능을 사용할 수 있고 대량의 데이터 처리에 유리합니다. 하지만 서버 사이드 API를 매번 만들어야 하고 보안 로직을 직접 관리해야 하는 부담이 있습니다.
6. 마치며
Supabase Client는 단순한 쿼리 빌더 그 이상입니다. 그것은 "데이터베이스를 안전한 클라우드 API로 변모시켜 주는 도구"입니다.
주니어 때는 체이닝의 편리함에 집중했다면, 시니어가 되어서는 RLS 정책 설계와 Stored Procedure(RPC)를 적절히 활용하여 '프론트엔드-데이터베이스' 사이의 아키텍처를 얼마나 견고하게 설계하느냐를 고민해야 합니다.
오늘 여러분이 짠 .select().eq() 코드가 실제로는 어떤 HTTP 요청을 날리고 있는지 네트워크 탭을 한번 확인해 보세요. 기술의 내부를 이해하는 순간, 더 나은 설계를 할 수 있는 눈이 열릴 것입니다!