supabase-expert
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSupabase Expert
Supabase专家
Overview
概述
Comprehensive guidance for working with Supabase including database operations, authentication, storage, edge functions, and Next.js integration. Enforces security patterns, performance optimizations, and modern best practices.
提供与Supabase相关的全面指导,包括数据库操作、认证、存储、边缘函数以及与Next.js的集成。遵循安全模式、性能优化和现代最佳实践。
Critical Rules
关键规则
API Keys (New System)
API密钥(新系统)
Supabase now offers two key types with improved security:
| Key Type | Prefix | Safety | Use Case |
|---|---|---|---|
| Publishable | | Safe for client | Browser, mobile, CLI |
| Secret | | Backend only | Servers, Edge Functions |
| Legacy anon | JWT-based | Safe for client | Being deprecated |
| Legacy service_role | JWT-based | Backend only | Being deprecated |
Key Rules:
- Secret keys return HTTP 401 if used in browser
- New keys support independent rotation without downtime
- Migrate from legacy keys when possible
See for migration guide and security practices.
references/api-keys.mdSupabase现在提供两种密钥类型,安全性有所提升:
| 密钥类型 | 前缀 | 安全性 | 使用场景 |
|---|---|---|---|
| Publishable | | 客户端安全 | 浏览器、移动端、CLI |
| Secret | | 仅后端可用 | 服务器、Edge Functions |
| 旧版anon | 基于JWT | 客户端安全 | 即将被弃用 |
| 旧版service_role | 基于JWT | 仅后端可用 | 即将被弃用 |
密钥规则:
- Secret密钥在浏览器中使用会返回HTTP 401
- 新密钥支持独立轮换,无需停机
- 尽可能从旧版密钥迁移
迁移指南和安全实践请参考。
references/api-keys.mdAuthentication SSR Rules
认证SSR规则
NEVER USE (DEPRECATED):
- Individual cookie methods: ,
get(),set()remove() - Package:
@supabase/auth-helpers-nextjs
ALWAYS USE:
- Package:
@supabase/ssr - Cookie methods: and
getAll()ONLYsetAll() - Proxy (formerly Middleware) MUST call to refresh session
getUser() - Proxy MUST return object
supabaseResponse
Important: As of Next.js 16+, useinstead ofproxy.ts. See https://nextjs.org/docs/app/api-reference/file-conventions/proxymiddleware.ts
See for complete patterns.
references/auth-ssr-patterns.md绝对不要使用(已弃用):
- 独立Cookie方法:、
get()、set()remove() - 包:
@supabase/auth-helpers-nextjs
必须使用:
- 包:
@supabase/ssr - Cookie方法:仅使用和
getAll()setAll() - 代理(原中间件)必须调用以刷新会话
getUser() - 代理必须返回对象
supabaseResponse
重要提示: 从Next.js 16+开始,使用替代proxy.ts。详情请见https://nextjs.org/docs/app/api-reference/file-conventions/proxymiddleware.ts
完整实现模式请参考。
references/auth-ssr-patterns.mdRLS Policy Rules
RLS策略规则
- Always wrap functions in SELECT: not
(SELECT auth.uid())auth.uid() - SELECT: USING only (no WITH CHECK)
- INSERT: WITH CHECK only (no USING)
- UPDATE: Both USING and WITH CHECK
- DELETE: USING only (no WITH CHECK)
- Always specify or
TO authenticatedTO anon - Create indexes on ALL columns used in policies
- NEVER use - create 4 separate policies
FOR ALL
See for performance-optimized templates.
references/rls-policy-patterns.md- 始终将函数包裹在SELECT中:使用而非
(SELECT auth.uid())auth.uid() - SELECT操作:仅使用USING(不使用WITH CHECK)
- INSERT操作:仅使用WITH CHECK(不使用USING)
- UPDATE操作:同时使用USING和WITH CHECK
- DELETE操作:仅使用USING(不使用WITH CHECK)
- 始终指定或
TO authenticatedTO anon - 为策略中使用的所有列创建索引
- 绝对不要使用- 分别创建4个独立的策略
FOR ALL
性能优化模板请参考。
references/rls-policy-patterns.mdDatabase Function Rules
数据库函数规则
- DEFAULT: Use (safer than DEFINER)
SECURITY INVOKER - ALWAYS: Set for security
search_path = '' - USE: Fully qualified names ()
public.table_name - SPECIFY: Correct volatility (IMMUTABLE/STABLE/VOLATILE)
- AVOID: unless absolutely required
SECURITY DEFINER
- 默认设置:使用(比DEFINER更安全)
SECURITY INVOKER - 必须设置:为安全起见,设置
search_path = '' - 使用规范:使用完全限定名称(如)
public.table_name - 明确指定:正确的易变性(IMMUTABLE/STABLE/VOLATILE)
- 避免使用:除非绝对必要,否则不要使用
SECURITY DEFINER
Edge Function Rules
Edge Functions规则
- USE: (not old serve import)
Deno.serve - IMPORTS: Always use prefix with version numbers
npm:/jsr:/node: - SHARED: Place shared code in folder
_shared/ - FILES: Write only to directory
/tmp - NEVER: Use bare specifiers or cross-function dependencies
See for complete templates.
references/edge-function-templates.md- 使用方式:(不要使用旧的serve导入)
Deno.serve - 导入规范:始终使用带版本号的前缀
npm:/jsr:/node: - 共享代码:将共享代码放在文件夹中
_shared/ - 文件操作:仅写入目录
/tmp - 禁止操作:不要使用裸导入标识符或跨函数依赖
完整模板请参考。
references/edge-function-templates.mdStorage Rules
存储规则
- Enable RLS on storage buckets
- Use signed URLs for private content
- Apply image transformations via URL parameters
- Leverage CDN for public assets
See for setup and patterns.
references/storage-patterns.md- 为存储桶启用RLS
- 对私有内容使用签名URL
- 通过URL参数应用图片转换
- 为公共资源使用CDN
设置和实现模式请参考。
references/storage-patterns.mdWorkflow Decision Tree
工作流决策树
User mentions database/Supabase work?
├─> Creating new tables?
│ └─> Use: Table Creation Workflow
├─> Creating RLS policies?
│ └─> Use: RLS Policy Workflow (references/rls-policy-patterns.md)
├─> Creating database function?
│ └─> Use: Database Function Workflow (references/sql-templates.md)
├─> Setting up Auth?
│ └─> Use: Auth SSR Workflow (references/auth-ssr-patterns.md)
├─> Creating Edge Function?
│ └─> Use: Edge Function Workflow (references/edge-function-templates.md)
├─> Setting up Storage?
│ └─> Use: Storage Workflow (references/storage-patterns.md)
├─> Next.js integration?
│ └─> Use: Next.js Patterns (references/nextjs-caveats.md)
└─> API key questions?
└─> Use: API Keys Guide (references/api-keys.md)用户提到数据库/Supabase相关工作?
├─> 是否创建新表?
│ └─> 使用:表创建工作流
├─> 是否创建RLS策略?
│ └─> 使用:RLS策略工作流(参考references/rls-policy-patterns.md)
├─> 是否创建数据库函数?
│ └─> 使用:数据库函数工作流(参考references/sql-templates.md)
├─> 是否设置认证?
│ └─> 使用:Auth SSR工作流(参考references/auth-ssr-patterns.md)
├─> 是否创建Edge Function?
│ └─> 使用:Edge Functions工作流(参考references/edge-function-templates.md)
├─> 是否设置存储?
│ └─> 使用:存储工作流(参考references/storage-patterns.md)
├─> 是否进行Next.js集成?
│ └─> 使用:Next.js实现模式(参考references/nextjs-caveats.md)
└─> 是否有API密钥相关问题?
└─> 使用:API密钥指南(参考references/api-keys.md)Table Creation Workflow
表创建工作流
When to use: Creating new database tables.
-
Design table structure:
- (UUID PRIMARY KEY)
id - ,
created_at(TIMESTAMPTZ)updated_at - (UUID reference to auth.users or profiles)
created_by - Use snake_case for all identifiers
- Add comments on all tables
-
Follow template:sql
CREATE TABLE IF NOT EXISTS public.table_name ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, status TEXT DEFAULT 'active', created_by UUID REFERENCES auth.users(id), created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); COMMENT ON TABLE public.table_name IS 'Description'; ALTER TABLE public.table_name ENABLE ROW LEVEL SECURITY; CREATE INDEX idx_table_name_status ON public.table_name(status); -
Enable RLS and create policies
-
Create TypeScript types for type safety
See for complete templates.
references/sql-templates.md适用场景: 创建新数据库表时。
-
设计表结构:
- (UUID主键)
id - 、
created_at(TIMESTAMPTZ类型)updated_at - (UUID类型,关联auth.users或profiles表)
created_by - 所有标识符使用蛇形命名法(snake_case)
- 为所有表添加注释
-
遵循模板:sql
CREATE TABLE IF NOT EXISTS public.table_name ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, status TEXT DEFAULT 'active', created_by UUID REFERENCES auth.users(id), created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); COMMENT ON TABLE public.table_name IS 'Description'; ALTER TABLE public.table_name ENABLE ROW LEVEL SECURITY; CREATE INDEX idx_table_name_status ON public.table_name(status); -
启用RLS并创建策略
-
创建TypeScript类型以保证类型安全
完整模板请参考。
references/sql-templates.mdAuth SSR Quick Reference
Auth SSR快速参考
Browser Client:
typescript
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
)
}Server Client:
typescript
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() { return cookieStore.getAll() },
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
} catch { /* Ignore in Server Components */ }
},
},
}
)
}Proxy (Critical) - replaces middleware.ts:
typescript
// proxy.ts (at root or src/ directory)
import { createServerClient } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'
export async function proxy(request: NextRequest) {
let supabaseResponse = NextResponse.next({ request })
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() { return request.cookies.getAll() },
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value }) =>
request.cookies.set(name, value)
)
supabaseResponse = NextResponse.next({ request })
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
},
},
}
)
// CRITICAL: Must call getUser() to refresh session
await supabase.auth.getUser()
return supabaseResponse // MUST return supabaseResponse
}浏览器客户端:
typescript
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
)
}服务器客户端:
typescript
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() { return cookieStore.getAll() },
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
} catch { /* 在Server Components中忽略 */ }
},
},
}
)
}代理(关键组件)- 替代middleware.ts:
typescript
// proxy.ts(位于根目录或src/目录)
import { createServerClient } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'
export async function proxy(request: NextRequest) {
let supabaseResponse = NextResponse.next({ request })
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() { return request.cookies.getAll() },
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value }) =>
request.cookies.set(name, value)
)
supabaseResponse = NextResponse.next({ request })
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
},
},
}
)
// 关键步骤:必须调用getUser()以刷新会话
await supabase.auth.getUser()
return supabaseResponse // 必须返回supabaseResponse
}RLS Policy Quick Reference
RLS策略快速参考
| Operation | USING | WITH CHECK |
|---|---|---|
| SELECT | Required | Ignored |
| INSERT | Ignored | Required |
| UPDATE | Required | Required |
| DELETE | Required | Ignored |
Example Policy:
sql
CREATE POLICY "Users view own records"
ON public.table_name
FOR SELECT
TO authenticated
USING ((SELECT auth.uid()) = user_id);| 操作 | USING | WITH CHECK |
|---|---|---|
| SELECT | 必填 | 忽略 |
| INSERT | 忽略 | 必填 |
| UPDATE | 必填 | 必填 |
| DELETE | 必填 | 忽略 |
示例策略:
sql
CREATE POLICY "Users view own records"
ON public.table_name
FOR SELECT
TO authenticated
USING ((SELECT auth.uid()) = user_id);Storage Quick Reference
存储快速参考
Create bucket:
sql
INSERT INTO storage.buckets (id, name, public)
VALUES ('avatars', 'avatars', false);Storage policy:
sql
CREATE POLICY "Users upload own avatar"
ON storage.objects
FOR INSERT
TO authenticated
WITH CHECK (
bucket_id = 'avatars' AND
(SELECT auth.uid())::text = (storage.foldername(name))[1]
);Image transformation URL:
/storage/v1/object/public/bucket/image.jpg?width=200&height=200&resize=cover创建存储桶:
sql
INSERT INTO storage.buckets (id, name, public)
VALUES ('avatars', 'avatars', false);存储策略:
sql
CREATE POLICY "Users upload own avatar"
ON storage.objects
FOR INSERT
TO authenticated
WITH CHECK (
bucket_id = 'avatars' AND
(SELECT auth.uid())::text = (storage.foldername(name))[1]
);图片转换URL:
/storage/v1/object/public/bucket/image.jpg?width=200&height=200&resize=coverEdge Function Quick Reference
Edge Functions快速参考
typescript
import { createClient } from 'npm:@supabase/supabase-js@2'
Deno.serve(async (req: Request) => {
if (req.method === 'OPTIONS') {
return new Response('ok', {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, content-type',
}
})
}
// User-scoped client (respects RLS)
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_PUBLISHABLE_KEY')!,
{ global: { headers: { Authorization: req.headers.get('Authorization')! } } }
)
// Admin client (bypasses RLS) - use SUPABASE_SECRET_KEY for admin operations
// const adminClient = createClient(
// Deno.env.get('SUPABASE_URL')!,
// Deno.env.get('SUPABASE_SECRET_KEY')!
// )
// Your logic here
return new Response(JSON.stringify({ success: true }), {
headers: { 'Content-Type': 'application/json' }
})
})typescript
import { createClient } from 'npm:@supabase/supabase-js@2'
Deno.serve(async (req: Request) => {
if (req.method === 'OPTIONS') {
return new Response('ok', {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, content-type',
}
})
}
// 用户范围客户端(遵循RLS)
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_PUBLISHABLE_KEY')!,
{ global: { headers: { Authorization: req.headers.get('Authorization')! } } }
)
// 管理员客户端(绕过RLS)- 对于管理员操作,使用SUPABASE_SECRET_KEY
// const adminClient = createClient(
// Deno.env.get('SUPABASE_URL')!,
// Deno.env.get('SUPABASE_SECRET_KEY')!
// )
// 在此处编写你的业务逻辑
return new Response(JSON.stringify({ success: true }), {
headers: { 'Content-Type': 'application/json' }
})
})PostgreSQL Style Guide
PostgreSQL风格指南
- lowercase for SQL keywords
- snake_case for tables and columns
- Plural table names (users, orders)
- Singular column names (user_id, order_date)
- Schema prefix in queries (public.users)
- Comments on all tables
- ISO 8601 dates
- SQL关键字使用小写
- 表和列使用蛇形命名法(snake_case)
- 表名使用复数形式(如users、orders)
- 列名使用单数形式(如user_id、order_date)
- 查询中使用架构前缀(如public.users)
- 为所有表添加注释
- 使用ISO 8601格式日期
Pre-Flight Checklist
预检查清单
Before ANY Supabase work:
- Using publishable key () for client code
sb_publishable_... - Using secret key () only in secure backend
sb_secret_... - Following table naming conventions
- Enabled RLS on tables
- Created indexes for policy columns
- Wrapped auth functions in SELECT
- Using @supabase/ssr with getAll/setAll
- Edge Functions using Deno.serve
- Imports have version numbers
在进行任何Supabase工作之前:
- 客户端代码使用publishable密钥()
sb_publishable_... - 仅在安全后端使用secret密钥()
sb_secret_... - 遵循表命名规范
- 为表启用RLS
- 为策略列创建索引
- 将auth函数包裹在SELECT中
- 使用@supabase/ssr并配合getAll/setAll方法
- Edge Functions使用Deno.serve
- 导入时包含版本号
Resources
资源
Reference Files (Load as needed)
参考文件(按需加载)
- - New API key system, migration guide
references/api-keys.md - - Storage setup, RLS, transformations
references/storage-patterns.md - - Next.js specific patterns and gotchas
references/nextjs-caveats.md - - Complete SQL templates
references/sql-templates.md - - Performance-optimized RLS patterns
references/rls-policy-patterns.md - - Complete Auth SSR implementation
references/auth-ssr-patterns.md - - Edge function templates
references/edge-function-templates.md
- - 新API密钥系统、迁移指南
references/api-keys.md - - 存储设置、RLS、转换功能
references/storage-patterns.md - - Next.js特定实现模式和注意事项
references/nextjs-caveats.md - - 完整SQL模板
references/sql-templates.md - - 性能优化的RLS模式
references/rls-policy-patterns.md - - 完整的Auth SSR实现
references/auth-ssr-patterns.md - - Edge Functions模板
references/edge-function-templates.md
Common Mistakes to Avoid
需避免的常见错误
- Using auth.uid() without wrapping in SELECT
- Forgetting to create indexes on policy columns
- Using SECURITY DEFINER by default
- Mixing individual cookie methods (get/set/remove)
- Using bare import specifiers in Edge Functions
- Using secret keys in browser code
- Not calling getUser() in proxy
- Not returning supabaseResponse from proxy
- Using middleware.ts instead of proxy.ts (deprecated in Next.js 16+)
- 未将auth.uid()包裹在SELECT中使用
- 忘记为策略列创建索引
- 默认使用SECURITY DEFINER
- 混合使用独立Cookie方法(get/set/remove)
- 在Edge Functions中使用裸导入标识符
- 在浏览器代码中使用secret密钥
- 未在代理中调用getUser()
- 未从代理返回supabaseResponse
- 在Next.js 16+中仍使用middleware.ts而非proxy.ts
Auth Providers Supported
支持的认证提供商
Supabase Auth supports 20+ OAuth providers:
- Google, GitHub, GitLab, Bitbucket
- Apple, Microsoft, Facebook, Twitter
- Discord, Slack, Spotify, Twitch
- LinkedIn, Notion, Figma, Zoom
- Phone auth (Twilio, MessageBird, Vonage)
- Anonymous sign-ins
- Enterprise SSO (SAML)
See for provider setup.
references/auth-ssr-patterns.mdSkill Version: 2.0.0
Last Updated: 2025-01-01
Documentation: https://supabase.com/docs
Supabase Auth支持20多种OAuth提供商:
- Google、GitHub、GitLab、Bitbucket
- Apple、Microsoft、Facebook、Twitter
- Discord、Slack、Spotify、Twitch
- LinkedIn、Notion、Figma、Zoom
- 手机号认证(Twilio、MessageBird、Vonage)
- 匿名登录
- 企业SSO(SAML)
提供商设置请参考。
references/auth-ssr-patterns.md技能版本: 2.0.0
最后更新: 2025-01-01
文档地址: https://supabase.com/docs