Supabaseとは
SupabaseとはBackend機能を簡単に使用できるBackend as a Service(BaaS/バース)プラットフォーム。
主に以下の機能を提供します。
| 機能名 | 説明 |
|---|---|
| Database | フルマネージドなPostgreSQLを提供し、RowLevelSecurityを備えたREST / GraphQL APIを自動生成する。アプリ側から安全にデータを読み書きできる。 |
| Auth | 一連のIDプロバイダーとAPIを通じて、プロジェクトへのメール・パスワード・パスワードレス・OAuth・モバイルログインを追加および管理することが可能。 |
| Storage | 行レベルのセキュリティアクセスポリシーを使用してPostgresデータベースと完全に統合され、大容量ファイルの保存・整理・交換・提供が可能。 |
| Edge Functions | グローバルに分散されたサーバー側関数により、ユーザーに最も近い場所でコードを実行し、レイテンシを最小限に抑えることが可能。 |
| Realtime | データベースの変更をリッスンしたり、クライアント間でユーザーの状態を保存・同期したり、チャネルにサブスクライブしているクライアントにデータをブロードキャストすることが可能。 |
Supabase EdgeFunction
Supabase EdgeFunctionは、Denoランタイム上で動作するTypeScript/JavaScriptベースのサーバーレス関数です。
AWS LambdaやCloudflare Workersのように、サーバーを立てずにHTTPリクエストで実行できる関数をデプロイ可能です。
仕組み
- リクエストがエッジゲートウェイ(リレー)に入ると、ゲートウェイはトラフィックをルーティング、認証ヘッダー/JWT検証を処理し、ルーティング/トラフィックルールを適用する。
- 認証とポリシーが適用される。ゲートウェイは、コードを実行する前にSupabase JWTを検証、レート制限を適用し、セキュリティチェックを集中管理できる。
- エッジランタイムが関数を実行する。関数は、ユーザーに最も近い地域に分散されたエッジランタイムノードで実行されるため、レイテンシが最小に抑えられる。
- 統合とデータアクセス-関数は一般的にSupabase API(Auth,Postgres,Storage)または、サードパーティAPIを呼び出す。
- 可観測性とログ-呼び出しにより、ダッシュボードまたはダウンストリームモニタリング(Sentryなど)で調べることができるログとメトリックスが生成される。
- 応答はゲートウェイ経由で返される。ゲートウェイは応答をクライアントに転送し、要求のメタデータを記録する。
EdgeFunctionを使用する場合
- 低レイテンシが必要な認証済みまたはパブリックHTTPエンドポイント
- Webhookレシーバー(Stripe,Githubなど)
- オンデマンドの画像またはOpenGraphの生成
- 小規模なAI推論タスクまたは外部LLM APIへの呼び出しのオーケストレーション
- トランザクションメールの送信
- Slack,Discordなどのメッセージングボットの構築
実装例
画像をStorageバケットにアップロードすると、自動でその情報を Postgres のテーブルに保存する仕組みを実装します。
構成イメージ:
- ユーザーが画像をimagesバケットにアップロード
- storage.objectsテーブルへのINSERTをきっかけにDatabase Webhookが発火
- Webhook → EdgeFunction store-image-meta を HTTP POST
- EgeFunction内:
- Webhook のペイロードから bucket_id, name, path_tokens などを取得
- public.image_files テーブルに INSERT
準備
Supabase CLIの構築
# Supabase CLIのインストール
brew install supabase/tap/supabase
# プロジェクト初期化(未実施の場合)
supabase init
# 関数を作成
supabase functions new store-image-meta
# TypeScriptの方を作成(任意)
supabase gen types typescript \
--project-id your-project-ref \
--schema storage,public \
> supabase/functions/store-image-meta/types.ts
実行すると、以下の構成が作成される
supabase/
functions/
store-image-meta/
index.ts
deno.json
types.ts
Storageバケットとテーブルを用意する
Storageバケット imagesを作成
Supabase Dashboardから:
- Storage→「new bucket」
- Bucket name:images
画像メタ情報を保存するテーブルを作成
SQL Editerから:
以下のSQLをペースト→Run CTRL
- テーブル名:image_files
- カラム:
- id:uuid (storage.objects.idを参照する外部キー)
- bucket_id(どのバケットか)
- path(パス文字列)
- name(ファイル名)
- uploaded_at
- カラム:
create table public.image_files (
id uuid primary key references storage.objects(id) on delete cascade,
bucket_id text not null,
path text not null,
name text not null,
uploaded_at timestamptz not null default now()
);
EdgeFunctionの実装
// supabase/functions/store-image-meta/index.ts
import { serve } from "https://deno.land/std@0.177.0/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";
// storage.objects の1行をざっくり表す型
type StorageObjectRow = {
id: string;
bucket_id: string;
name: string;
path_tokens: string[] | null;
};
// Database Webhook から飛んでくるペイロード
type WebhookPayload = {
type: "INSERT" | "UPDATE" | "DELETE";
table: string;
schema: string;
record: StorageObjectRow;
old_record: StorageObjectRow | null;
};
const SUPABASE_URL = Deno.env.get("SUPABASE_URL") ?? "";
const SERVICE_ROLE_KEY = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "";
console.log("[init] SUPABASE_URL set:", !!SUPABASE_URL);
console.log("[init] SERVICE_ROLE_KEY set:", !!SERVICE_ROLE_KEY);
const supabaseAdmin = createClient(SUPABASE_URL, SERVICE_ROLE_KEY);
serve(async (req) => {
try {
const payload = (await req.json()) as WebhookPayload;
const record = payload.record;
// INSERT 以外はスキップ(UPDATE/DELETE が飛んでくる可能性に備えて)
if (payload.type !== "INSERT") {
console.log("[hook] skip type:", payload.type);
return new Response("skip", { status: 200 });
}
const path =
(record.path_tokens && record.path_tokens.join("/")) || record.name;
console.log("[hook] new object:", {
id: record.id,
bucket_id: record.bucket_id,
path,
name: record.name,
});
// image_files にメタ情報を保存
const { error } = await supabaseAdmin
.from("image_files")
.insert({
id: record.id,
bucket_id: record.bucket_id,
path,
name: record.name,
});
if (error) {
console.error("[hook] insert error:", error);
return new Response(
JSON.stringify({ error: error.message }),
{
status: 500,
headers: { "Content-Type": "application/json" },
},
);
}
console.log("[hook] insert success");
return new Response("ok", { status: 200 });
} catch (err) {
console.error("[hook] unhandled error:", err);
return new Response("Internal Server Error", { status: 500 });
}
});
必要な環境変数を設定
EdgeFunctionの実行環境に、以下の環境変数を設定:
- SUPABASE_URL:プロジェクトURL(デプロイ時に自動で入るので通常は明示設定不要)。
- SUPABASE_SERVICE_ROLE_KEY:ServiceRoleキー(デプロイ時に自動で入るので通常は明示設定不要)。
Supabase CLIから設定する場合は:
supabase secrets set SUPABASE_SERVICE_ROLE_KEY="your_service_role_key"
関数をデプロイ
Supabaseプロジェクトとローカルを紐づけたうえで、EdgeFunctionをデプロイする
# プロジェクトとリンク(まだの場合)
supabase link --project-ref your-project-ref
# 関数をデプロイ
supabase functions deploy store-image-meta
DatabaseWebhookで自動実行
Dashboardから:
- 「Database」 → 「Webhooks」
- enable webhooksをONに設定
- 「Create a new hook」
- Table: storage.objects
- Event: INSERT(新しい画像がアップロードされたとき)
- Webhook type: Edge Function
- Function name: store-image-meta
こうしておくと、Storage に画像がアップロードされるたびに Edge Function が自動実行されます。
動作確認
- Dashboardから:
- 「Storage」 → 「images」バケットに適当な画像をアップロード
- トリガーに Webhook → EdgeFunction store-image-meta が呼ばれる
- Edge Function が public.image_files にメタデータをコピー
- 「Table Editor」 → 「image_files」テーブルにレコードが存在するかを確認
参考元








