Supabase 새 테이블, RLS만 켜면 안 돼요 — 2026-05-30 GRANT 변경
Supabase에서 테이블을 만들고 RLS 정책까지 걸었는데, 클라이언트에서 조회하면 권한 오류가 나거나 테이블이 아예 안 보이는 경우가 있어요. 2026년 5월 30일부터 새 프로젝트의 기본 동작이 바뀌었거든요. 새로 만든 public 스키마 테이블은 권한을 명시하기 전에는 Data API에 노출되지 않아요.
무엇이 바뀌었나요
예전에는 public 스키마에 테이블을 만들면 자동으로 API에 노출됐어요. 이제는 역할별로 권한을 직접 줘야 보여요. 적용 일정은 이래요.
2026-04-28 새 프로젝트에서 '자동 노출 끄기'를 선택할 수 있게 됨
2026-05-30 새 프로젝트의 기본값으로 전환 (몇 주에 걸쳐 점진 적용)
2026-10-30 기존 프로젝트 전체에 적용
이미 만들어 둔 테이블은 기존 권한을 그대로 유지해서 당장은 영향이 없어요. 다만 10월 30일에는 기존 프로젝트도 같은 규칙으로 통일돼요.

RLS와 GRANT는 서로 다른 일을 해요
이 둘은 헷갈리기 쉬운데, 막는 지점이 달라요.
- GRANT: 어떤 역할이 이 테이블을 건드릴 수 있는지를 정해요. 없으면 API가 테이블 자체를 못 봐서 권한 오류(
42501)가 나요. 이때 PostgREST가 어떤 역할에 어떤 권한이 필요한지, 실행할 GRANT 문까지 에러에 적어줘요. - 정책(POLICY): GRANT를 통과한 다음, 어떤 행을 볼 수 있는지를 정해요. 정책이 없으면 RLS가 모든 행을 막아서 0건이 나와요.
정리하면 GRANT는 문을 여는 일, 정책은 그 안에서 어떤 행을 보여줄지 고르는 일이에요. 둘 다 있어야 정상 동작해요.

새 테이블 표준 패턴
그래서 새 테이블 마이그레이션은 네 단계로 묶어 두면 편해요. 테이블 생성 → RLS 켜기 → GRANT → 정책 순서예요.
CREATE TABLE public.posts (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES auth.users(id),
title text NOT NULL,
is_published boolean NOT NULL DEFAULT false
);
ALTER TABLE public.posts ENABLE ROW LEVEL SECURITY;
GRANT SELECT ON public.posts TO anon;
GRANT SELECT, INSERT, UPDATE, DELETE ON public.posts TO authenticated;
CREATE POLICY "posts_select" ON public.posts
FOR SELECT
USING (is_published = true OR auth.uid() = user_id);
공개되면 안 되는 개인 데이터 테이블은 anon에는 GRANT를 주지 않으면 돼요. 그러면 비로그인 사용자는 접근 자체가 막혀요.
기존 프로젝트는 미리 점검해요
10월 30일 전환 전에 GRANT가 빠진 테이블이 없는지 확인해 두면 안전해요. Supabase 대시보드의 Security Advisor가 테이블별로 누락된 권한을 잡아줘요. 마이그레이션으로 권한을 관리한다면, 권한 현황을 한 번 쿼리해서 빠진 곳을 미리 채워 두면 10월 전환 때 당황할 일이 없어요.
정리
핵심은 두 가지예요. 2026년 5월 30일부터 새 public 테이블은 GRANT를 명시해야 API에 보이고, GRANT와 정책은 각각 '테이블 접근'과 '행 필터'라는 다른 일을 해서 둘 다 있어야 동작해요. 새 테이블을 만들 때 네 단계(생성·RLS·GRANT·정책)를 한 묶음으로 적어 두면 실수가 줄어요.
이 글의 원문은 라이프케어로그 기술 블로그에 있어요 → Supabase 새 테이블, RLS만 켜면 안 돼요 — 2026-05-30 GRANT 변경