개인의 기록
  • 소개
  • 프로젝트
  • 글
  • 링크

© 2026 newgirok

← 글 목록

Supabase Realtime — 데이터베이스 변경을 실시간으로 구독

2025년 4월 16일
SupabaseRealtimeSubscribeChannelWebSocket

서버를 폴링하지 않아도 데이터베이스에 새 행이 INSERT되는 순간 클라이언트가 즉시 알 수 있다면 어떨까. Supabase Realtime은 PostgreSQL의 논리 복제(Logical Replication)를 WebSocket 위에 올려 이를 가능하게 한다. 채팅, 알림, 실시간 대시보드처럼 "변경 즉시 반응"이 필요한 기능을 폴링 없이 구현할 수 있다.

동작 원리

PostgreSQL WAL
     │  (logical replication slot)
     ▼
Supabase Realtime Server
     │  (WebSocket / Phoenix Channel)
     ▼
Browser / Mobile Client

PostgreSQL은 모든 변경 사항을 WAL(Write-Ahead Log)에 기록한다. Supabase Realtime 서버는 논리 복제 슬롯을 통해 WAL을 읽고, 변경 이벤트를 Channel로 묶어 WebSocket으로 브로드캐스트한다.

WAL(Write-Ahead Log) — PostgreSQL이 데이터 변경 전에 먼저 기록하는 순차 로그. 논리 복제는 이 로그를 행(row) 단위 이벤트로 디코딩한다.

Channel 설정

Supabase Realtime의 구독 단위는 Channel이다. 하나의 Channel은 테이블 전체, 특정 필터 조건, 또는 Broadcast/Presence 이벤트를 담을 수 있다.

import { createClient } from '@supabase/supabase-js'

const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY)

const channel = supabase
  .channel('messages-changes')
  .on(
    'postgres_changes',
    { event: '*', schema: 'public', table: 'messages' },
    (payload) => console.log('변경 수신:', payload)
  )
  .subscribe()

Channel — Supabase Realtime에서 이벤트를 그룹화하는 논리 단위. Phoenix Framework의 Channel 개념을 그대로 사용한다.

INSERT / UPDATE / DELETE 구독

event 필드로 수신할 이벤트 종류를 제한할 수 있다.

event 값수신 시점
INSERT새 행 삽입 시
UPDATE기존 행 수정 시
DELETE행 삭제 시
*세 가지 모두

특정 조건만 구독하려면 filter 옵션을 추가한다.

.on(
  'postgres_changes',
  {
    event: 'INSERT',
    schema: 'public',
    table: 'messages',
    filter: 'room_id=eq.42',
  },
  (payload) => {
    const newMessage = payload.new
    appendMessage(newMessage)
  }
)

실전 예시

채팅 앱 — messages 테이블의 INSERT를 구독해 상대방 메시지를 폴링 없이 화면에 추가한다.

알림 시스템 — notifications 테이블에 새 행이 생기면 즉시 토스트 UI를 띄운다.

실시간 대시보드 — orders 테이블의 UPDATE를 구독해 주문 상태 변경을 차트에 반영한다.

// 알림 구독 예시
supabase
  .channel('user-notifications')
  .on(
    'postgres_changes',
    {
      event: 'INSERT',
      schema: 'public',
      table: 'notifications',
      filter: `user_id=eq.${currentUserId}`,
    },
    ({ new: notif }) => showToast(notif.message)
  )
  .subscribe()

RLS와 보안

Realtime 구독도 Row Level Security(RLS)의 적용을 받는다. 테이블에 RLS가 활성화되어 있으면 구독자는 자신이 SELECT 권한을 가진 행의 이벤트만 수신한다. 구독 자체가 RLS를 우회하지 않으므로, 기존 정책만 올바르게 설정되어 있으면 추가 보안 코드는 불필요하다.

-- 본인 메시지만 볼 수 있는 정책
CREATE POLICY "본인 메시지만 조회"
  ON messages FOR SELECT
  USING (auth.uid() = user_id);

구독을 해제할 때는 channel.unsubscribe를 호출하거나, supabase.removeChannel(channel)로 Channel 자체를 제거한다.

← 이전 글Supabase Storage — 파일을 저장하고 제공하는 방법
다음 글 →Supabase RPC — PostgreSQL 함수를 API처럼 호출하는 방법