
Supabaseを利用しているプロジェクトにおいて、クライアントライブラリ(supabase-js)やREST API、GraphQL経由でデータを取得・更新しようとした際に「42501」や「permission denied for table」というエラーが発生し、データにアクセスできなくなる事例が増えています。
このエラーの主な原因は、Supabaseが実施している「Data APIにおけるpublicスキーマの自動公開廃止」という仕様変更です。従来はpublicスキーマに新規テーブルを作成すると自動的にAPI経由でアクセス可能になっていましたが、今後はテーブルごとに明示的な権限付与(GRANT)が必須となりました。
特に、2026年10月30日からはすべての既存プロジェクトに対してもこの新仕様が強制適用されます。既存のテーブルはそのまま動作するものの、新しく追加したテーブルやローカル開発環境でのマイグレーション(supabase db reset)を実行した際に、突然APIから到達不能になる落とし穴が存在します。
この記事では、この仕様変更の影響範囲、エラーが発生したテーブルの特定方法、SQLを用いた正確なGRANT権限付与手順、CLIマイグレーション運用の注意点、そして毎回GRANTを書く手間を省く自動化テクニックまでを詳しく解説します。
この記事で行うこと
前提条件・検証環境
注意点:影響を受ける通信と受けない通信
今回の仕様変更は、SupabaseのData API(PostgRESTやGraphQL)を経由する通信にのみ適用されます。
| 接続方式 | 利用ツール・ライブラリ | 仕様変更の影響 |
|---|---|---|
| Data API経由 | supabase-js、REST API、GraphQL | 影響あり(明示的なGRANTが必須) |
| PostgreSQL直接接続 | Prisma、Drizzle ORM、TypeORM、psql | 影響なし(接続文字列による直接操作は維持) |
| 管理ダッシュボード | Table Editor、SQL Editor | 影響なし(管理者権限で直接操作可能) |
PrismaやDrizzleなどのORMを利用し、サーバーサイドから直接データベース接続文字列(ポート5432やSupavisor経由のプールポート)で接続している場合は、本仕様変更による影響を受けません。
仕様変更の概要とスケジュール
この変更は、意図しないテーブルのデータ流出を防ぎ、「最小権限の原則」をデフォルトで徹底するために導入されました。
従来は、publicスキーマにテーブルを作成すると、PostgreSQLの内部ロールである anon(未ログイン)、authenticated(ログイン済み)、service_role(管理者)に対して、自動的にCRUD権限が付与されていました。そのため、Row Level Security(RLS)の設定を忘れると即座に全データが外部へ露出するリスクがありました。
新仕様では、テーブル作成直後の初期状態ではAPIからテーブルに一切アクセスできなくなります。
既存プロジェクトで既に稼働している既存テーブルについては、10月30日以降も現在の権限がそのまま維持されるため、既存機能が突然停止することはありません。問題となるのは、「今後新しくテーブルを作成する場合」です。
手順1:影響を受けるテーブルの確認方法
新規テーブルを作成した後にAPIからデータを取得しようとして失敗する場合、どのようなエラーが出るのか、ダッシュボードのどこで確認できるのかを把握しましょう。
1. エラーメッセージの確認
権限が付与されていないテーブルに supabase-js 等からアクセスすると、PostgreSQLのエラーコード 42501 とともに以下のようなエラーレスポンスが返されます。
{
"code": "42501",
"details": null,
"hint": "Grant the required privileges to the current role with: GRANT SELECT ON public.your_table TO anon;",
"message": "permission denied for table your_table"
}
SupabaseのData APIは親切に設計されており、エラーレスポンス内の hint プロパティに「不足している権限を付与するための正確なSQL文」を提示してくれます。このヒントを確認することで、どのロールに何の権限が不足しているかを即座に特定できます。なお、hint の文面はPostgRESTのバージョンや状況によって異なる場合があります。
2. ダッシュボードでの公開状況確認
ダッシュボード上からどのテーブルがData APIに公開されているかを一覧確認できます。
- Supabase Dashboardにログインし、プロジェクトを開きます。
- 左メニューの「Project Settings」から「Data API」(または「Integrations」内の「Data API」)を開きます。
- 「Exposed Tables」のセクションを確認し、アクセスさせたいテーブルが含まれているかをチェックします。
- また、「Advisors」メニューの「Security Advisor」を開くことで、Data APIへの露出設定やRLSポリシーが未設定のテーブルを一括検知できます。
手順2:SQLで必要な権限(GRANT)を明示的に付与する
エラーを解消してテーブルをAPIに公開するには、対象テーブルに対して適切なロールへの権限を付与します。Supabaseダッシュボードの「SQL Editor」を開き、用途に応じたSQLを実行します。
1. ログインユーザー(authenticated)にCRUD操作を許可する
一般的なアプリケーションにおいて、認証済みユーザーからのアクセスを許可する場合は、authenticated ロールに権限を付与します。
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE public.your_table TO authenticated;
2. 未ログインユーザー(anon)に閲覧のみを許可する
ランディングページの記事一覧や公開プロフィールなど、ログイン前のユーザーにも閲覧を許可する場合は、anon ロールに SELECT 権限を付与します。
GRANT SELECT ON TABLE public.your_table TO anon;
3. バックエンド管理者(service_role)への付与漏れに注意する
多くの開発者がハマる最大の落とし穴が、この service_role への権限付与漏れです。
Next.jsのServer ActionsやRoute Handlers、あるいはNode.jsバッチ処理などにおいて、RLSをバイパスするために SUPABASE_SERVICE_ROLE_KEY を用いてクライアントを生成している場合でも、テーブル自体に対する権限がなければData API経由のアクセスは 42501 エラーで弾かれます。
サーバーサイドから操作を行うテーブルには、必ず service_role に対する権限も付与してください。
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE public.your_table TO service_role;
4. RLS(行レベルセキュリティ)の有効化とポリシー作成
GRANTによってAPIからテーブルに到達できるようになった後は、必ずRLSを有効にして各行のアクセス制御を定義します。GRANTだけでは全レコードの操作が許可されてしまうため、RLSによる保護が不可欠です。
-- RLSを有効化
ALTER TABLE public.your_table ENABLE ROW LEVEL SECURITY;
-- ログイン中の本人のデータのみ参照可能にするポリシー例
CREATE POLICY "Users can read own data" ON public.your_table
FOR SELECT TO authenticated
USING (auth.uid() = user_id);
テーブル作成、GRANTによる権限付与、RLS有効化とポリシー定義の3つを1つのセットとして扱うことが基本原則となります。
手順3:Supabase CLI・マイグレーション運用の落とし穴と対策
チーム開発やローカル環境でSupabase CLIを使用している場合、今回の仕様変更は開発フロー全体に影響を及ぼします。
マイグレーションファイルにGRANT文をセットで書く
これまで supabase/migrations/ 配下に作成していたマイグレーションファイルは、CREATE TABLE だけを書いて完了としていたケースが一般的でした。
しかし今後は、マイグレーションファイル内にテーブル作成とGRANT文を同一トランザクションとして記述する必要があります。
-- supabase/migrations/20261030000000_create_posts_table.sql
-- 1. テーブルの作成
CREATE TABLE public.posts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
content TEXT,
user_id UUID REFERENCES auth.users(id),
created_at TIMESTAMPTZ DEFAULT now() NOT NULL
);
-- 2. Data API用ロールへの権限付与(必須)
GRANT SELECT ON TABLE public.posts TO anon;
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE public.posts TO authenticated;
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE public.posts TO service_role;
-- 3. RLSの有効化とポリシー設定
ALTER TABLE public.posts ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Allow public read" ON public.posts
FOR SELECT USING (true);
CREATE POLICY "Allow authenticated insert" ON public.posts
FOR INSERT TO authenticated
WITH CHECK (auth.uid() = user_id);
supabase db reset や Preview Branch の破損に注意する
過去に作成したマイグレーションファイルにGRANT文が含まれていない場合、以下の場面でトラブルが発生します。
この問題を防ぐため、既存のマイグレーションファイルを一括で見直し、GRANT文を追加するか、後述するデフォルト権限設定のマイグレーションを先頭に配置することを推奨します。
手順4:毎回GRANTを書くのが面倒な場合の解決策(ALTER DEFAULT PRIVILEGES)
新しいテーブルを作るたびに毎回3つのロールにGRANT文を書くのが手間に感じる場合や、以前の自動公開挙動を維持したい場合は、PostgreSQLの「デフォルト権限設定(ALTER DEFAULT PRIVILEGES)」を活用するのが有効です。
以下のSQLを実行しておくと、指定したスキーマ内で今後新しく作成されるすべてのテーブルに対して、指定した権限が自動的に適用されます。
-- 今後 public スキーマに作成されるすべてのテーブルに自動で権限を付与する
-- FOR ROLE postgres を明示することで、postgresロールが作成するテーブルに確実に適用される
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public
GRANT SELECT ON TABLES TO anon;
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO authenticated, service_role;
このSQLを初期マイグレーションファイル(またはダッシュボードのSQL Editor)で1度実行しておけば、テーブル作成時に毎回個別のGRANT文を書く必要がなくなり、従来の開発体験に近い形で運用できます。
なお、ALTER DEFAULT PRIVILEGES は実行以降に作成される新規テーブルにのみ適用されます。すでに存在する既存テーブルへの権限付与は、個別の GRANT 文で別途実行する必要があります。
ただし、この設定を行うと作成したテーブルが自動的にAPIに露出することになるため、RLSの有効化忘れにはこれまで以上に注意してください。
参考:BaaSに依存しない直接接続・別インフラ構成の検討
今回の仕様変更のように、BaaS(Backend as a Service)独自のアクセス制御ルールやAPI仕様の変更に振り回されたくない場合は、アーキテクチャを見直すこともひとつの選択肢です。
1. サーバーサイドからの直接接続(Prisma / Drizzle)
Next.jsやRemix、Expressなどのバックエンドを持つ構成であれば、クライアントサイドから直接 supabase-js を叩くのではなく、サーバーサイドからPrismaやDrizzle ORM経由で直接データベースに接続する形にシフトします。
2. 独立したAPIサーバー(Cloud Run)や別DB(Neon)への移行
システムの規模が大きくなった場合や、より柔軟なインフラ制御を求める場合は、マネージドコンテナ環境への分離も検討できます。
よくある質問
Q. RLS(行レベルセキュリティ)を設定していればGRANTは不要ですか?
いいえ、必要です。PostgreSQLのアクセス判定では、RLSポリシーの評価よりも手前の段階で「テーブル自体への操作権限(GRANT)」がチェックされます。テーブルへの権限がない場合はRLSを評価することなく即座に 42501 エラーとなるため、GRANTとRLSの両方を設定する必要があります。
Q. service_roleキーを使っているのにエラーが出るのはなぜですか?
service_role キーはRLSをバイパスしますが、テーブルそのものに対するアクセス権限(GRANT)がない場合はアクセスできません。新仕様では service_role ロールに対しても明示的なGRANTが必要です。
Q. 2026年10月30日を過ぎると、現在本番で動いている既存テーブルは止まりますか?
停止しません。10月30日の強制適用は「新しく作成されるテーブル」が対象であり、既存プロジェクトに既に存在するテーブルの権限が自動的に剥奪されることはありません。ただし、10月30日以降に新規テーブルを追加する際や、DBマイグレーションを実行する際には対応が必要になります。
まとめ
SupabaseのData API仕様変更は、データベースのセキュリティを「最小権限の原則」に適合させるための重要なステップです。
10月30日の強制適用を前にマイグレーションフローと権限設定を見直し、予期せぬAPI停止トラブルを未然に防ぎましょう。
次に読むおすすめ記事

参考情報
PostgreSQL Documentation: ALTER DEFAULT PRIVILEGES
Supabase Official Documentation: Database Access Control and Grants

