supabase-functions
Denoランタイムでサーバーレス機能やAPIエンドポイントなどを開発・デプロイするために、Supabase Edge Functionsを活用し、Webhookやタスクの自動化などを実現するSkill。
📜 元の英語説明(参考)
Supabase Edge Functions development and deployment using Deno runtime. Use when creating serverless functions, webhooks, API endpoints, or scheduled tasks.
🇯🇵 日本人クリエイター向け解説
Denoランタイムでサーバーレス機能やAPIエンドポイントなどを開発・デプロイするために、Supabase Edge Functionsを活用し、Webhookやタスクの自動化などを実現するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o supabase-functions.zip https://jpskill.com/download/9503.zip && unzip -o supabase-functions.zip && rm supabase-functions.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/9503.zip -OutFile "$d\supabase-functions.zip"; Expand-Archive "$d\supabase-functions.zip" -DestinationPath $d -Force; ri "$d\supabase-functions.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
supabase-functions.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
supabase-functionsフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
Supabase Edge Functions Skill
Deno ランタイムを使用したサーバーレス関数です。
クイックリファレンス
| タスク | コマンド |
|---|---|
| 関数を作成 | supabase functions new <name> |
| ローカルで実行 | supabase functions serve |
| デプロイ | supabase functions deploy <name> |
| 削除 | supabase functions delete <name> |
| シークレットを設定 | supabase secrets set KEY=value |
| シークレットをリスト表示 | supabase secrets list |
関数を作成
supabase functions new hello-world
以下を作成: supabase/functions/hello-world/index.ts
基本的な関数構造
// supabase/functions/hello-world/index.ts
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
Deno.serve(async (req: Request) => {
const { name } = await req.json()
return new Response(
JSON.stringify({ message: `Hello ${name}!` }),
{ headers: { "Content-Type": "application/json" } }
)
})
ローカル開発
すべての関数を実行
supabase functions serve
環境変数を使用して実行
supabase functions serve --env-file .env
JWT 検証なしで実行
supabase functions serve --no-verify-jwt
関数をテスト
curl -i --request POST \
'http://localhost:54321/functions/v1/hello-world' \
--header 'Authorization: Bearer <ANON_KEY>' \
--header 'Content-Type: application/json' \
--data '{"name":"World"}'
CORS 処理
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}
Deno.serve(async (req: Request) => {
// Handle CORS preflight
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders })
}
try {
const { name } = await req.json()
return new Response(
JSON.stringify({ message: `Hello ${name}!` }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
)
} catch (error) {
return new Response(
JSON.stringify({ error: error.message }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 400 }
)
}
})
Supabase Client の使用
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
import { createClient } from 'jsr:@supabase/supabase-js@2'
Deno.serve(async (req: Request) => {
// Create Supabase client with service role
const supabaseAdmin = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? ''
)
// Or with user's JWT (respects RLS)
const authHeader = req.headers.get('Authorization')!
const supabaseClient = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_ANON_KEY') ?? '',
{ global: { headers: { Authorization: authHeader } } }
)
// Query with user context
const { data, error } = await supabaseClient
.from('posts')
.select('*')
return new Response(
JSON.stringify({ data, error }),
{ headers: { 'Content-Type': 'application/json' } }
)
})
JWT からユーザーを取得
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
import { createClient } from 'jsr:@supabase/supabase-js@2'
Deno.serve(async (req: Request) => {
const supabaseClient = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_ANON_KEY') ?? '',
{ global: { headers: { Authorization: req.headers.get('Authorization')! } } }
)
const { data: { user }, error } = await supabaseClient.auth.getUser()
if (error || !user) {
return new Response(
JSON.stringify({ error: 'Unauthorized' }),
{ status: 401, headers: { 'Content-Type': 'application/json' } }
)
}
return new Response(
JSON.stringify({ userId: user.id, email: user.email }),
{ headers: { 'Content-Type': 'application/json' } }
)
})
環境変数とシークレット
シークレットを設定
# 単一のシークレット
supabase secrets set API_KEY=abc123
# 複数のシークレット
supabase secrets set API_KEY=abc123 DB_PASSWORD=secret
# ファイルから
supabase secrets set --env-file .env
関数内でアクセス
const apiKey = Deno.env.get('API_KEY')
const supabaseUrl = Deno.env.get('SUPABASE_URL')
const supabaseKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')
組み込み変数
SUPABASE_URL- プロジェクト URLSUPABASE_ANON_KEY- Anon keySUPABASE_SERVICE_ROLE_KEY- Service role keySUPABASE_DB_URL- 直接データベース接続
関数をデプロイ
単一の関数をデプロイ
supabase functions deploy hello-world
JWT 検証なしでデプロイ
supabase functions deploy webhook-handler --no-verify-jwt
すべての関数をデプロイ
supabase functions deploy
JavaScript から呼び出す
const { data, error } = await supabase.functions.invoke('hello-world', {
body: { name: 'World' }
})
カスタムヘッダーを使用
const { data, error } = await supabase.functions.invoke('api-handler', {
body: { action: 'create' },
headers: { 'x-custom-header': 'value' }
})
Webhook 関数
// supabase/functions/stripe-webhook/index.ts
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
import Stripe from 'npm:stripe@14'
const stripe = new Stripe(Deno.env.get('STRIPE_SECRET_KEY')!, {
apiVersion: '2023-10-16'
})
const cryptoProvider = Stripe.createSubtleCryptoProvider()
Deno.serve(async (req: Request) => {
const signature = req.headers.get('Stripe-Signature')!
const body = await req.text()
let event: Stripe.Event
try {
event = await stripe.webhooks.constructEventAsync(
body,
signature,
Deno.env.get('STRIPE_WEBHOOK_SECRET')!,
undefined,
cryptoProvider
)
} catch (err) {
return new Response(
JSON.stringify({ error: `Webhook Error: ${err.message}` }),
{ status: 400 }
)
}
switch (event.type) {
case 'checkout.session.completed':
(原文がここで切り詰められています) 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Supabase Edge Functions Skill
Serverless functions with Deno runtime.
Quick Reference
| Task | Command |
|---|---|
| Create function | supabase functions new <name> |
| Serve locally | supabase functions serve |
| Deploy | supabase functions deploy <name> |
| Delete | supabase functions delete <name> |
| Set secrets | supabase secrets set KEY=value |
| List secrets | supabase secrets list |
Create Function
supabase functions new hello-world
Creates: supabase/functions/hello-world/index.ts
Basic Function Structure
// supabase/functions/hello-world/index.ts
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
Deno.serve(async (req: Request) => {
const { name } = await req.json()
return new Response(
JSON.stringify({ message: `Hello ${name}!` }),
{ headers: { "Content-Type": "application/json" } }
)
})
Local Development
Serve All Functions
supabase functions serve
Serve with Environment Variables
supabase functions serve --env-file .env
Serve without JWT Verification
supabase functions serve --no-verify-jwt
Test Function
curl -i --request POST \
'http://localhost:54321/functions/v1/hello-world' \
--header 'Authorization: Bearer <ANON_KEY>' \
--header 'Content-Type: application/json' \
--data '{"name":"World"}'
CORS Handling
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}
Deno.serve(async (req: Request) => {
// Handle CORS preflight
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders })
}
try {
const { name } = await req.json()
return new Response(
JSON.stringify({ message: `Hello ${name}!` }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
)
} catch (error) {
return new Response(
JSON.stringify({ error: error.message }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 400 }
)
}
})
Using Supabase Client
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
import { createClient } from 'jsr:@supabase/supabase-js@2'
Deno.serve(async (req: Request) => {
// Create Supabase client with service role
const supabaseAdmin = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? ''
)
// Or with user's JWT (respects RLS)
const authHeader = req.headers.get('Authorization')!
const supabaseClient = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_ANON_KEY') ?? '',
{ global: { headers: { Authorization: authHeader } } }
)
// Query with user context
const { data, error } = await supabaseClient
.from('posts')
.select('*')
return new Response(
JSON.stringify({ data, error }),
{ headers: { 'Content-Type': 'application/json' } }
)
})
Get User from JWT
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
import { createClient } from 'jsr:@supabase/supabase-js@2'
Deno.serve(async (req: Request) => {
const supabaseClient = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_ANON_KEY') ?? '',
{ global: { headers: { Authorization: req.headers.get('Authorization')! } } }
)
const { data: { user }, error } = await supabaseClient.auth.getUser()
if (error || !user) {
return new Response(
JSON.stringify({ error: 'Unauthorized' }),
{ status: 401, headers: { 'Content-Type': 'application/json' } }
)
}
return new Response(
JSON.stringify({ userId: user.id, email: user.email }),
{ headers: { 'Content-Type': 'application/json' } }
)
})
Environment Variables & Secrets
Set Secrets
# Single secret
supabase secrets set API_KEY=abc123
# Multiple secrets
supabase secrets set API_KEY=abc123 DB_PASSWORD=secret
# From file
supabase secrets set --env-file .env
Access in Function
const apiKey = Deno.env.get('API_KEY')
const supabaseUrl = Deno.env.get('SUPABASE_URL')
const supabaseKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')
Built-in Variables
SUPABASE_URL- Project URLSUPABASE_ANON_KEY- Anon keySUPABASE_SERVICE_ROLE_KEY- Service role keySUPABASE_DB_URL- Direct database connection
Deploy Function
Deploy Single Function
supabase functions deploy hello-world
Deploy without JWT Verification
supabase functions deploy webhook-handler --no-verify-jwt
Deploy All Functions
supabase functions deploy
Invoke from JavaScript
const { data, error } = await supabase.functions.invoke('hello-world', {
body: { name: 'World' }
})
With Custom Headers
const { data, error } = await supabase.functions.invoke('api-handler', {
body: { action: 'create' },
headers: { 'x-custom-header': 'value' }
})
Webhook Function
// supabase/functions/stripe-webhook/index.ts
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
import Stripe from 'npm:stripe@14'
const stripe = new Stripe(Deno.env.get('STRIPE_SECRET_KEY')!, {
apiVersion: '2023-10-16'
})
const cryptoProvider = Stripe.createSubtleCryptoProvider()
Deno.serve(async (req: Request) => {
const signature = req.headers.get('Stripe-Signature')!
const body = await req.text()
let event: Stripe.Event
try {
event = await stripe.webhooks.constructEventAsync(
body,
signature,
Deno.env.get('STRIPE_WEBHOOK_SECRET')!,
undefined,
cryptoProvider
)
} catch (err) {
return new Response(
JSON.stringify({ error: `Webhook Error: ${err.message}` }),
{ status: 400 }
)
}
switch (event.type) {
case 'checkout.session.completed':
const session = event.data.object
// Handle successful checkout
break
default:
console.log(`Unhandled event type ${event.type}`)
}
return new Response(JSON.stringify({ received: true }))
})
Database Webhook
Trigger function on database changes:
-- Create webhook trigger
CREATE OR REPLACE FUNCTION notify_function()
RETURNS trigger AS $$
BEGIN
PERFORM net.http_post(
url := 'https://<project>.supabase.co/functions/v1/handle-insert',
headers := '{"Authorization": "Bearer <SERVICE_KEY>"}'::jsonb,
body := row_to_json(NEW)::text
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER on_insert
AFTER INSERT ON posts
FOR EACH ROW
EXECUTE FUNCTION notify_function();
Scheduled Functions (Cron)
-- Using pg_cron extension
SELECT cron.schedule(
'daily-cleanup',
'0 0 * * *', -- Every day at midnight
$$
SELECT net.http_post(
url := 'https://<project>.supabase.co/functions/v1/cleanup',
headers := '{"Authorization": "Bearer <SERVICE_KEY>"}'::jsonb
)
$$
);
Configuration (config.toml)
[functions.hello-world]
verify_jwt = true
[functions.webhook-handler]
verify_jwt = false
[functions.api-handler]
verify_jwt = true
import_map = "./supabase/functions/import_map.json"
Shared Code
Create _shared folder for reusable code:
supabase/functions/
├── _shared/
│ ├── cors.ts
│ └── supabase.ts
├── hello-world/
│ └── index.ts
└── api-handler/
└── index.ts
// _shared/cors.ts
export const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}
// _shared/supabase.ts
import { createClient } from 'jsr:@supabase/supabase-js@2'
export const supabaseAdmin = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
)
// hello-world/index.ts
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
import { corsHeaders } from '../_shared/cors.ts'
import { supabaseAdmin } from '../_shared/supabase.ts'
Deno.serve(async (req: Request) => {
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders })
}
// Use shared client
const { data } = await supabaseAdmin.from('posts').select('*')
return new Response(
JSON.stringify({ data }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
)
})
Limits
| Limit | Value |
|---|---|
| CPU Time | 2 seconds |
| Request Timeout | 150 seconds |
| Wall Clock (Pro) | 400 seconds |
| Bundle Size | 20 MB |
References
- function-patterns.md - Common patterns
- deno-imports.md - Import syntax