supabase-expert

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Supabase 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 TypePrefixSafetyUse Case
Publishable
sb_publishable_...
Safe for clientBrowser, mobile, CLI
Secret
sb_secret_...
Backend onlyServers, Edge Functions
Legacy anonJWT-basedSafe for clientBeing deprecated
Legacy service_roleJWT-basedBackend onlyBeing 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
references/api-keys.md
for migration guide and security practices.
Supabase现在提供两种密钥类型,安全性有所提升:
密钥类型前缀安全性使用场景
Publishable
sb_publishable_...
客户端安全浏览器、移动端、CLI
Secret
sb_secret_...
仅后端可用服务器、Edge Functions
旧版anon基于JWT客户端安全即将被弃用
旧版service_role基于JWT仅后端可用即将被弃用
密钥规则:
  • Secret密钥在浏览器中使用会返回HTTP 401
  • 新密钥支持独立轮换,无需停机
  • 尽可能从旧版密钥迁移
迁移指南和安全实践请参考
references/api-keys.md

Authentication SSR Rules

认证SSR规则

NEVER USE (DEPRECATED):
  • Individual cookie methods:
    get()
    ,
    set()
    ,
    remove()
  • Package:
    @supabase/auth-helpers-nextjs
ALWAYS USE:
  • Package:
    @supabase/ssr
  • Cookie methods:
    getAll()
    and
    setAll()
    ONLY
  • Proxy (formerly Middleware) MUST call
    getUser()
    to refresh session
  • Proxy MUST return
    supabaseResponse
    object
Important: As of Next.js 16+, use
proxy.ts
instead of
middleware.ts
. See https://nextjs.org/docs/app/api-reference/file-conventions/proxy
See
references/auth-ssr-patterns.md
for complete patterns.
绝对不要使用(已弃用):
  • 独立Cookie方法:
    get()
    set()
    remove()
  • 包:
    @supabase/auth-helpers-nextjs
必须使用:
  • 包:
    @supabase/ssr
  • Cookie方法:仅使用
    getAll()
    setAll()
  • 代理(原中间件)必须调用
    getUser()
    以刷新会话
  • 代理必须返回
    supabaseResponse
    对象
重要提示: 从Next.js 16+开始,使用
proxy.ts
替代
middleware.ts
。详情请见https://nextjs.org/docs/app/api-reference/file-conventions/proxy
完整实现模式请参考
references/auth-ssr-patterns.md

RLS Policy Rules

RLS策略规则

  • Always wrap functions in SELECT:
    (SELECT auth.uid())
    not
    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
    TO authenticated
    or
    TO anon
  • Create indexes on ALL columns used in policies
  • NEVER use
    FOR ALL
    - create 4 separate policies
See
references/rls-policy-patterns.md
for performance-optimized templates.
  • 始终将函数包裹在SELECT中:使用
    (SELECT auth.uid())
    而非
    auth.uid()
  • SELECT操作:仅使用USING(不使用WITH CHECK)
  • INSERT操作:仅使用WITH CHECK(不使用USING)
  • UPDATE操作:同时使用USING和WITH CHECK
  • DELETE操作:仅使用USING(不使用WITH CHECK)
  • 始终指定
    TO authenticated
    TO anon
  • 为策略中使用的所有列创建索引
  • 绝对不要使用
    FOR ALL
    - 分别创建4个独立的策略
性能优化模板请参考
references/rls-policy-patterns.md

Database Function Rules

数据库函数规则

  • DEFAULT: Use
    SECURITY INVOKER
    (safer than DEFINER)
  • ALWAYS: Set
    search_path = ''
    for security
  • USE: Fully qualified names (
    public.table_name
    )
  • SPECIFY: Correct volatility (IMMUTABLE/STABLE/VOLATILE)
  • AVOID:
    SECURITY DEFINER
    unless absolutely required
  • 默认设置:使用
    SECURITY INVOKER
    (比DEFINER更安全)
  • 必须设置:为安全起见,设置
    search_path = ''
  • 使用规范:使用完全限定名称(如
    public.table_name
  • 明确指定:正确的易变性(IMMUTABLE/STABLE/VOLATILE)
  • 避免使用:除非绝对必要,否则不要使用
    SECURITY DEFINER

Edge Function Rules

Edge Functions规则

  • USE:
    Deno.serve
    (not old serve import)
  • IMPORTS: Always use
    npm:/jsr:/node:
    prefix with version numbers
  • SHARED: Place shared code in
    _shared/
    folder
  • FILES: Write only to
    /tmp
    directory
  • NEVER: Use bare specifiers or cross-function dependencies
See
references/edge-function-templates.md
for complete templates.
  • 使用方式
    Deno.serve
    (不要使用旧的serve导入)
  • 导入规范:始终使用带版本号的
    npm:/jsr:/node:
    前缀
  • 共享代码:将共享代码放在
    _shared/
    文件夹中
  • 文件操作:仅写入
    /tmp
    目录
  • 禁止操作:不要使用裸导入标识符或跨函数依赖
完整模板请参考
references/edge-function-templates.md

Storage Rules

存储规则

  • Enable RLS on storage buckets
  • Use signed URLs for private content
  • Apply image transformations via URL parameters
  • Leverage CDN for public assets
See
references/storage-patterns.md
for setup and patterns.
  • 为存储桶启用RLS
  • 对私有内容使用签名URL
  • 通过URL参数应用图片转换
  • 为公共资源使用CDN
设置和实现模式请参考
references/storage-patterns.md

Workflow 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.
  1. Design table structure:
    • id
      (UUID PRIMARY KEY)
    • created_at
      ,
      updated_at
      (TIMESTAMPTZ)
    • created_by
      (UUID reference to auth.users or profiles)
    • Use snake_case for all identifiers
    • Add comments on all tables
  2. 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);
  3. Enable RLS and create policies
  4. Create TypeScript types for type safety
See
references/sql-templates.md
for complete templates.
适用场景: 创建新数据库表时。
  1. 设计表结构:
    • id
      (UUID主键)
    • created_at
      updated_at
      (TIMESTAMPTZ类型)
    • created_by
      (UUID类型,关联auth.users或profiles表)
    • 所有标识符使用蛇形命名法(snake_case)
    • 为所有表添加注释
  2. 遵循模板:
    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);
  3. 启用RLS并创建策略
  4. 创建TypeScript类型以保证类型安全
完整模板请参考
references/sql-templates.md

Auth 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策略快速参考

OperationUSINGWITH CHECK
SELECTRequiredIgnored
INSERTIgnoredRequired
UPDATERequiredRequired
DELETERequiredIgnored
Example Policy:
sql
CREATE POLICY "Users view own records"
ON public.table_name
FOR SELECT
TO authenticated
USING ((SELECT auth.uid()) = user_id);
操作USINGWITH 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=cover

Edge 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 (
    sb_publishable_...
    ) for client code
  • Using secret key (
    sb_secret_...
    ) only in secure backend
  • 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)

参考文件(按需加载)

  • references/api-keys.md
    - New API key system, migration guide
  • references/storage-patterns.md
    - Storage setup, RLS, transformations
  • references/nextjs-caveats.md
    - Next.js specific patterns and gotchas
  • references/sql-templates.md
    - Complete SQL templates
  • references/rls-policy-patterns.md
    - Performance-optimized RLS patterns
  • references/auth-ssr-patterns.md
    - Complete Auth SSR implementation
  • references/edge-function-templates.md
    - Edge function templates
  • references/api-keys.md
    - 新API密钥系统、迁移指南
  • references/storage-patterns.md
    - 存储设置、RLS、转换功能
  • references/nextjs-caveats.md
    - Next.js特定实现模式和注意事项
  • references/sql-templates.md
    - 完整SQL模板
  • references/rls-policy-patterns.md
    - 性能优化的RLS模式
  • references/auth-ssr-patterns.md
    - 完整的Auth SSR实现
  • references/edge-function-templates.md
    - Edge Functions模板

Common Mistakes to Avoid

需避免的常见错误

  1. Using auth.uid() without wrapping in SELECT
  2. Forgetting to create indexes on policy columns
  3. Using SECURITY DEFINER by default
  4. Mixing individual cookie methods (get/set/remove)
  5. Using bare import specifiers in Edge Functions
  6. Using secret keys in browser code
  7. Not calling getUser() in proxy
  8. Not returning supabaseResponse from proxy
  9. Using middleware.ts instead of proxy.ts (deprecated in Next.js 16+)
  1. 未将auth.uid()包裹在SELECT中使用
  2. 忘记为策略列创建索引
  3. 默认使用SECURITY DEFINER
  4. 混合使用独立Cookie方法(get/set/remove)
  5. 在Edge Functions中使用裸导入标识符
  6. 在浏览器代码中使用secret密钥
  7. 未在代理中调用getUser()
  8. 未从代理返回supabaseResponse
  9. 在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
references/auth-ssr-patterns.md
for provider setup.

Skill 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