supabase
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSupabase Core Skill
Supabase核心技能
Load with: base.md + [supabase-nextjs.md | supabase-python.md | supabase-node.md]
Core concepts, CLI workflow, and patterns common to all Supabase projects.
Sources: Supabase Docs | Supabase CLI
加载方式:base.md + [supabase-nextjs.md | supabase-python.md | supabase-node.md]
所有Supabase项目通用的核心概念、CLI工作流和模式。
资料来源: Supabase文档 | Supabase CLI
Core Principle
核心原则
Local-first, migrations in version control, never touch production directly.
Develop locally with the Supabase CLI, capture all changes as migrations, and deploy through CI/CD.
优先本地开发,迁移纳入版本控制,绝不直接修改生产环境。
使用Supabase CLI在本地开发,将所有变更捕获为迁移,并通过CI/CD部署。
Supabase Stack
Supabase技术栈
| Service | Purpose |
|---|---|
| Database | PostgreSQL with extensions |
| Auth | User authentication, OAuth providers |
| Storage | File storage with RLS |
| Edge Functions | Serverless Deno functions |
| Realtime | WebSocket subscriptions |
| Vector | AI embeddings (pgvector) |
| 服务 | 用途 |
|---|---|
| Database | 带扩展的PostgreSQL |
| Auth | 用户认证、OAuth提供商 |
| Storage | 带RLS的文件存储 |
| Edge Functions | 无服务器Deno函数 |
| Realtime | WebSocket订阅 |
| Vector | AI嵌入(pgvector) |
CLI Setup
CLI设置
Install & Login
安装与登录
bash
undefinedbash
undefinedmacOS
macOS
brew install supabase/tap/supabase
brew install supabase/tap/supabase
npm (alternative)
npm (替代方案)
npm install -g supabase
npm install -g supabase
Login
登录
supabase login
undefinedsupabase login
undefinedInitialize Project
初始化项目
bash
undefinedbash
undefinedIn your project directory
在你的项目目录中
supabase init
supabase init
Creates:
创建以下文件:
supabase/
supabase/
├── config.toml # Local config
├── config.toml # 本地配置
├── seed.sql # Seed data
├── seed.sql # 种子数据
└── migrations/ # SQL migrations
└── migrations/ # SQL迁移文件
undefinedundefinedLink to Remote
关联远程项目
bash
undefinedbash
undefinedGet project ref from dashboard URL: https://supabase.com/dashboard/project/<ref>
从控制台URL获取项目引用:https://supabase.com/dashboard/project/<ref>
supabase link --project-ref <project-id>
supabase link --project-ref <project-id>
Pull existing schema
拉取现有架构
supabase db pull
undefinedsupabase db pull
undefinedStart Local Stack
启动本地服务栈
bash
supabase startbash
supabase startOutput:
输出:
API URL: http://localhost:54321
API URL: http://localhost:54321
GraphQL URL: http://localhost:54321/graphql/v1
GraphQL URL: http://localhost:54321/graphql/v1
DB URL: postgresql://postgres:postgres@localhost:54322/postgres
DB URL: postgresql://postgres:postgres@localhost:54322/postgres
Studio URL: http://localhost:54323
Studio URL: http://localhost:54323
Anon key: eyJ...
Anon key: eyJ...
Service role key: eyJ...
Service role key: eyJ...
---
---Migration Workflow
迁移工作流
Option 1: Dashboard + Diff (Quick Prototyping)
选项1:控制台+差异对比(快速原型开发)
bash
undefinedbash
undefined1. Make changes in local Studio (localhost:54323)
1. 在本地Studio(localhost:54323)中进行变更
2. Generate migration from diff
2. 通过差异对比生成迁移文件
supabase db diff -f <migration_name>
supabase db diff -f <migration_name>
3. Review generated SQL
3. 查看生成的SQL
cat supabase/migrations/*_<migration_name>.sql
cat supabase/migrations/*_<migration_name>.sql
4. Reset to test
4. 重置数据库进行测试
supabase db reset
undefinedsupabase db reset
undefinedOption 2: Write Migrations Directly (Recommended)
选项2:直接编写迁移文件(推荐)
bash
undefinedbash
undefined1. Create empty migration
1. 创建空的迁移文件
supabase migration new create_users_table
supabase migration new create_users_table
2. Edit the migration file
2. 编辑迁移文件
supabase/migrations/<timestamp>_create_users_table.sql
supabase/migrations/<timestamp>_create_users_table.sql
3. Apply locally
3. 在本地应用迁移
supabase db reset
undefinedsupabase db reset
undefinedOption 3: ORM Migrations (Best DX)
选项3:ORM迁移(最佳开发体验)
Use Drizzle (TypeScript) or SQLAlchemy (Python) - see framework-specific skills.
使用Drizzle(TypeScript)或SQLAlchemy(Python)——详见框架专属技能文档。
Deploy Migrations
部署迁移
bash
undefinedbash
undefinedPush to remote (staging/production)
推送到远程环境(预发布/生产)
supabase db push
supabase db push
Check migration status
查看迁移状态
supabase migration list
---supabase migration list
---Database Patterns
数据库模式
Enable RLS on All Tables
为所有表启用RLS
sql
-- Always enable RLS
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
-- Default deny - must create policies
CREATE POLICY "Users can view own profile"
ON public.profiles
FOR SELECT
USING (auth.uid() = id);sql
-- 始终启用RLS
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
-- 默认拒绝访问 - 必须创建策略
CREATE POLICY "Users can view own profile"
ON public.profiles
FOR SELECT
USING (auth.uid() = id);Common RLS Policies
常见RLS策略
sql
-- Public read
CREATE POLICY "Public read access"
ON public.posts FOR SELECT
USING (true);
-- Authenticated users only
CREATE POLICY "Authenticated users can insert"
ON public.posts FOR INSERT
WITH CHECK (auth.role() = 'authenticated');
-- Owner access
CREATE POLICY "Users can update own records"
ON public.posts FOR UPDATE
USING (auth.uid() = user_id);
-- Admin access (using custom claim)
CREATE POLICY "Admins have full access"
ON public.posts FOR ALL
USING (auth.jwt() ->> 'role' = 'admin');sql
-- 公开读取
CREATE POLICY "Public read access"
ON public.posts FOR SELECT
USING (true);
-- 仅允许已认证用户
CREATE POLICY "Authenticated users can insert"
ON public.posts FOR INSERT
WITH CHECK (auth.role() = 'authenticated');
-- 所有者访问
CREATE POLICY "Users can update own records"
ON public.posts FOR UPDATE
USING (auth.uid() = user_id);
-- 管理员访问(使用自定义声明)
CREATE POLICY "Admins have full access"
ON public.posts FOR ALL
USING (auth.jwt() ->> 'role' = 'admin');Link to auth.users
关联auth.users表
sql
-- Profile table linked to auth
CREATE TABLE public.profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
username TEXT UNIQUE NOT NULL,
avatar_url TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Auto-create profile on signup
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.profiles (id, username)
VALUES (NEW.id, NEW.email);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();sql
-- 关联到认证系统的用户资料表
CREATE TABLE public.profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
username TEXT UNIQUE NOT NULL,
avatar_url TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 用户注册时自动创建资料
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.profiles (id, username)
VALUES (NEW.id, NEW.email);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();Seed Data
种子数据
supabase/seed.sql
supabase/seed.sql
sql
-- Runs on `supabase db reset`
-- Use ON CONFLICT for idempotency
INSERT INTO public.profiles (id, username, avatar_url)
VALUES
('d0e1f2a3-b4c5-6d7e-8f9a-0b1c2d3e4f5a', 'testuser', null),
('a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d', 'admin', null)
ON CONFLICT (id) DO NOTHING;sql
-- 在`supabase db reset`时执行
-- 使用ON CONFLICT保证幂等性
INSERT INTO public.profiles (id, username, avatar_url)
VALUES
('d0e1f2a3-b4c5-6d7e-8f9a-0b1c2d3e4f5a', 'testuser', null),
('a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d', 'admin', null)
ON CONFLICT (id) DO NOTHING;Environment Variables
环境变量
Required Variables
必填变量
bash
undefinedbash
undefinedPublic (safe for client-side)
公开变量(可安全用于客户端)
SUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_ANON_KEY=eyJ...
SUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_ANON_KEY=eyJ...
Private (server-side only - NEVER expose)
私有变量(仅用于服务端 - 绝不可暴露)
SUPABASE_SERVICE_ROLE_KEY=eyJ...
DATABASE_URL=postgresql://postgres.[ref]:[password]@aws-0-region.pooler.supabase.com:6543/postgres
undefinedSUPABASE_SERVICE_ROLE_KEY=eyJ...
DATABASE_URL=postgresql://postgres.[ref]:[password]@aws-0-region.pooler.supabase.com:6543/postgres
undefinedLocal vs Production
本地与生产环境对比
bash
undefinedbash
undefined.env.local (local development)
.env.local(本地开发)
SUPABASE_URL=http://localhost:54321
SUPABASE_ANON_KEY=<from supabase start>
DATABASE_URL=postgresql://postgres:postgres@localhost:54322/postgres
SUPABASE_URL=http://localhost:54321
SUPABASE_ANON_KEY=<来自supabase start的输出>
DATABASE_URL=postgresql://postgres:postgres@localhost:54322/postgres
.env.production (remote)
.env.production(远程环境)
SUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_ANON_KEY=<from dashboard>
DATABASE_URL=<connection pooler URL>
undefinedSUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_ANON_KEY=<来自控制台>
DATABASE_URL=<连接池URL>
undefinedConnection Pooling
连接池
bash
undefinedbash
undefinedTransaction mode (recommended for serverless)
事务模式(推荐用于无服务器环境)
Add ?pgbouncer=true to URL
在URL后添加?pgbouncer=true
DATABASE_URL=postgresql://...@pooler.supabase.com:6543/postgres?pgbouncer=true
DATABASE_URL=postgresql://...@pooler.supabase.com:6543/postgres?pgbouncer=true
Session mode (for migrations, long transactions)
会话模式(用于迁移、长事务)
DATABASE_URL=postgresql://...@pooler.supabase.com:5432/postgres
---DATABASE_URL=postgresql://...@pooler.supabase.com:5432/postgres
---Edge Functions
Edge Functions
Create Function
创建函数
bash
supabase functions new hello-worldbash
supabase functions new hello-worldBasic Structure
基础结构
typescript
// supabase/functions/hello-world/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
serve(async (req) => {
const { name } = await req.json();
return new Response(
JSON.stringify({ message: `Hello ${name}!` }),
{ headers: { 'Content-Type': 'application/json' } }
);
});typescript
// supabase/functions/hello-world/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
serve(async (req) => {
const { name } = await req.json();
return new Response(
JSON.stringify({ message: `Hello ${name}!` }),
{ headers: { 'Content-Type': 'application/json' } }
);
});With Auth Context
带认证上下文
typescript
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
serve(async (req) => {
const supabase = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_ANON_KEY') ?? '',
{
global: {
headers: { Authorization: req.headers.get('Authorization')! },
},
}
);
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
return new Response('Unauthorized', { status: 401 });
}
return new Response(JSON.stringify({ user_id: user.id }));
});typescript
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
serve(async (req) => {
const supabase = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_ANON_KEY') ?? '',
{
global: {
headers: { Authorization: req.headers.get('Authorization')! },
},
}
);
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
return new Response('Unauthorized', { status: 401 });
}
return new Response(JSON.stringify({ user_id: user.id }));
});Deploy
部署
bash
undefinedbash
undefinedServe locally
本地运行
supabase functions serve
supabase functions serve
Deploy single function
部署单个函数
supabase functions deploy hello-world
supabase functions deploy hello-world
Deploy all
部署所有函数
supabase functions deploy
---supabase functions deploy
---Storage
存储
Create Bucket (in migration)
创建存储桶(在迁移文件中)
sql
INSERT INTO storage.buckets (id, name, public)
VALUES ('avatars', 'avatars', true);
-- Storage policies
CREATE POLICY "Avatar images are publicly accessible"
ON storage.objects FOR SELECT
USING (bucket_id = 'avatars');
CREATE POLICY "Users can upload own avatar"
ON storage.objects FOR INSERT
WITH CHECK (
bucket_id = 'avatars' AND
auth.uid()::text = (storage.foldername(name))[1]
);sql
INSERT INTO storage.buckets (id, name, public)
VALUES ('avatars', 'avatars', true);
-- 存储策略
CREATE POLICY "Avatar images are publicly accessible"
ON storage.objects FOR SELECT
USING (bucket_id = 'avatars');
CREATE POLICY "Users can upload own avatar"
ON storage.objects FOR INSERT
WITH CHECK (
bucket_id = 'avatars' AND
auth.uid()::text = (storage.foldername(name))[1]
);CLI Quick Reference
CLI速查手册
bash
undefinedbash
undefinedLifecycle
生命周期
supabase start # Start local stack
supabase stop # Stop local stack
supabase status # Show status & credentials
supabase start # 启动本地服务栈
supabase stop # 停止本地服务栈
supabase status # 显示状态与凭证
Database
数据库
supabase db reset # Reset + migrations + seed
supabase db push # Push to remote
supabase db pull # Pull remote schema
supabase db diff -f <name> # Generate migration from diff
supabase db lint # Check for issues
supabase db reset # 重置数据库 + 执行迁移 + 种子数据
supabase db push # 推送到远程环境
supabase db pull # 拉取远程架构
supabase db diff -f <name> # 通过差异对比生成迁移文件
supabase db lint # 检查问题
Migrations
迁移
supabase migration new <name> # Create migration
supabase migration list # List migrations
supabase migration up # Apply pending (remote)
supabase migration new <name> # 创建迁移文件
supabase migration list # 列出迁移文件
supabase migration up # 应用待处理迁移(远程环境)
Functions
函数
supabase functions new <name> # Create function
supabase functions serve # Local dev
supabase functions deploy # Deploy all
supabase functions new <name> # 创建函数
supabase functions serve # 本地开发
supabase functions deploy # 部署所有函数
Types
类型生成
supabase gen types typescript --local > types/database.ts
supabase gen types typescript --local > types/database.ts
Project
项目管理
supabase link --project-ref <id> # Link to remote
supabase projects list # List projects
---supabase link --project-ref <id> # 关联到远程项目
supabase projects list # 列出项目
---CI/CD Template
CI/CD模板
yaml
undefinedyaml
undefined.github/workflows/supabase.yml
.github/workflows/supabase.yml
name: Supabase CI/CD
on:
push:
branches: [main]
pull_request:
env:
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_DB_PASSWORD }}
SUPABASE_PROJECT_ID: ${{ secrets.SUPABASE_PROJECT_ID }}
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: supabase/setup-cli@v1
- name: Start Supabase
run: supabase start
- name: Run migrations
run: supabase db reset
- name: Lint database
run: supabase db lintdeploy:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: supabase/setup-cli@v1
- name: Link project
run: supabase link --project-ref $SUPABASE_PROJECT_ID
- name: Push migrations
run: supabase db push
- name: Deploy functions
run: supabase functions deploy
---name: Supabase CI/CD
on:
push:
branches: [main]
pull_request:
env:
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_DB_PASSWORD }}
SUPABASE_PROJECT_ID: ${{ secrets.SUPABASE_PROJECT_ID }}
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: supabase/setup-cli@v1
- name: Start Supabase
run: supabase start
- name: Run migrations
run: supabase db reset
- name: Lint database
run: supabase db lintdeploy:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: supabase/setup-cli@v1
- name: Link project
run: supabase link --project-ref $SUPABASE_PROJECT_ID
- name: Push migrations
run: supabase db push
- name: Deploy functions
run: supabase functions deploy
---Anti-Patterns
反模式
- Direct production changes - Always use migrations
- Disabled RLS - Enable on all user-data tables
- Service key in client - Never expose service role key
- No connection pooling - Use pooler for serverless
- Committing .env - Add to .gitignore
- Skipping migration review - Always check generated SQL
- No seed data - Use seed.sql for consistent local dev
- 直接修改生产环境 - 始终使用迁移文件
- 禁用RLS - 为所有用户数据表启用RLS
- 客户端使用服务端密钥 - 绝不可暴露服务端角色密钥
- 未使用连接池 - 为无服务器环境使用连接池
- 提交.env文件 - 将其添加到.gitignore
- 跳过迁移文件审查 - 始终检查生成的SQL
- 无种子数据 - 使用seed.sql保证本地开发一致性