supabase by alinaqi/claude-bootstrap
npx skills add https://github.com/alinaqi/claude-bootstrap --skill supabase加载方式:base.md + [supabase-nextjs.md | supabase-python.md | supabase-node.md]
所有 Supabase 项目共有的核心概念、CLI 工作流和模式。
来源: Supabase 文档 | Supabase CLI
本地优先,版本控制中的迁移,绝不直接操作生产环境。
使用 Supabase CLI 在本地开发,将所有更改捕获为迁移,并通过 CI/CD 进行部署。
| 服务 | 用途 |
|---|---|
| 数据库 | 带有扩展的 PostgreSQL |
| 认证 | 用户认证,OAuth 提供商 |
| 存储 | 带有 RLS 的文件存储 |
| 边缘函数 | 无服务器 Deno 函数 |
| 实时 | WebSocket 订阅 |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 向量 |
| AI 嵌入 (pgvector) |
# macOS
brew install supabase/tap/supabase
# npm (替代方案)
npm install -g supabase
# 登录
supabase login
# 在你的项目目录中
supabase init
# 创建:
# supabase/
# ├── config.toml # 本地配置
# ├── seed.sql # 种子数据
# └── migrations/ # SQL 迁移文件
# 从仪表板 URL 获取项目引用:https://supabase.com/dashboard/project/<ref>
supabase link --project-ref <project-id>
# 拉取现有模式
supabase db pull
supabase start
# 输出:
# API URL: http://localhost:54321
# GraphQL URL: http://localhost:54321/graphql/v1
# DB URL: postgresql://postgres:postgres@localhost:54322/postgres
# Studio URL: http://localhost:54323
# Anon key: eyJ...
# Service role key: eyJ...
# 1. 在本地 Studio (localhost:54323) 中进行更改
# 2. 根据差异生成迁移
supabase db diff -f <migration_name>
# 3. 查看生成的 SQL
cat supabase/migrations/*_<migration_name>.sql
# 4. 重置以进行测试
supabase db reset
# 1. 创建空迁移
supabase migration new create_users_table
# 2. 编辑迁移文件
# supabase/migrations/<timestamp>_create_users_table.sql
# 3. 在本地应用
supabase db reset
使用 Drizzle (TypeScript) 或 SQLAlchemy (Python) - 请参阅特定框架的技能。
# 推送到远程(暂存/生产环境)
supabase db push
# 检查迁移状态
supabase migration list
-- 始终启用 RLS
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
-- 默认拒绝 - 必须创建策略
CREATE POLICY "用户可以查看自己的个人资料"
ON public.profiles
FOR SELECT
USING (auth.uid() = id);
-- 公开读取
CREATE POLICY "公开读取权限"
ON public.posts FOR SELECT
USING (true);
-- 仅限认证用户
CREATE POLICY "认证用户可以插入"
ON public.posts FOR INSERT
WITH CHECK (auth.role() = 'authenticated');
-- 所有者访问
CREATE POLICY "用户可以更新自己的记录"
ON public.posts FOR UPDATE
USING (auth.uid() = user_id);
-- 管理员访问(使用自定义声明)
CREATE POLICY "管理员拥有完全访问权限"
ON public.posts FOR ALL
USING (auth.jwt() ->> 'role' = 'admin');
-- 链接到认证的用户资料表
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();
-- 在 `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;
# 公开(客户端安全)
SUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_ANON_KEY=eyJ...
# 私有(仅限服务器端 - 切勿暴露)
SUPABASE_SERVICE_ROLE_KEY=eyJ...
DATABASE_URL=postgresql://postgres.[ref]:[password]@aws-0-region.pooler.supabase.com:6543/postgres
# .env.local (本地开发)
SUPABASE_URL=http://localhost:54321
SUPABASE_ANON_KEY=<来自 supabase start>
DATABASE_URL=postgresql://postgres:postgres@localhost:54322/postgres
# .env.production (远程)
SUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_ANON_KEY=<来自仪表板>
DATABASE_URL=<连接池 URL>
# 事务模式(推荐用于无服务器)
# 在 URL 后添加 ?pgbouncer=true
DATABASE_URL=postgresql://...@pooler.supabase.com:6543/postgres?pgbouncer=true
# 会话模式(用于迁移、长事务)
DATABASE_URL=postgresql://...@pooler.supabase.com:5432/postgres
supabase functions new hello-world
// 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' } }
);
});
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('未经授权', { status: 401 });
}
return new Response(JSON.stringify({ user_id: user.id }));
});
# 本地服务
supabase functions serve
# 部署单个函数
supabase functions deploy hello-world
# 部署所有函数
supabase functions deploy
INSERT INTO storage.buckets (id, name, public)
VALUES ('avatars', 'avatars', true);
-- 存储策略
CREATE POLICY "头像图片可公开访问"
ON storage.objects FOR SELECT
USING (bucket_id = 'avatars');
CREATE POLICY "用户可以上传自己的头像"
ON storage.objects FOR INSERT
WITH CHECK (
bucket_id = 'avatars' AND
auth.uid()::text = (storage.foldername(name))[1]
);
# 生命周期
supabase start # 启动本地技术栈
supabase stop # 停止本地技术栈
supabase status # 显示状态和凭据
# 数据库
supabase db reset # 重置 + 迁移 + 种子数据
supabase db push # 推送到远程
supabase db pull # 拉取远程模式
supabase db diff -f <name> # 根据差异生成迁移
supabase db lint # 检查问题
# 迁移
supabase migration new <name> # 创建迁移
supabase migration list # 列出迁移
supabase migration up # 应用待处理的迁移(远程)
# 函数
supabase functions new <name> # 创建函数
supabase functions serve # 本地开发
supabase functions deploy # 部署所有函数
# 类型
supabase gen types typescript --local > types/database.ts
# 项目
supabase link --project-ref <id> # 链接到远程项目
supabase projects list # 列出项目
# .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: 启动 Supabase
run: supabase start
- name: 运行迁移
run: supabase db reset
- name: 检查数据库
run: supabase db lint
deploy:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: supabase/setup-cli@v1
- name: 链接项目
run: supabase link --project-ref $SUPABASE_PROJECT_ID
- name: 推送迁移
run: supabase db push
- name: 部署函数
run: supabase functions deploy
每周安装量
211
代码仓库
GitHub 星标数
530
首次出现
2026年1月20日
安全审计
安装于
opencode172
gemini-cli162
claude-code158
codex153
cursor140
github-copilot138
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
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.
| 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) |
# macOS
brew install supabase/tap/supabase
# npm (alternative)
npm install -g supabase
# Login
supabase login
# In your project directory
supabase init
# Creates:
# supabase/
# ├── config.toml # Local config
# ├── seed.sql # Seed data
# └── migrations/ # SQL migrations
# Get project ref from dashboard URL: https://supabase.com/dashboard/project/<ref>
supabase link --project-ref <project-id>
# Pull existing schema
supabase db pull
supabase start
# Output:
# API URL: http://localhost:54321
# GraphQL URL: http://localhost:54321/graphql/v1
# DB URL: postgresql://postgres:postgres@localhost:54322/postgres
# Studio URL: http://localhost:54323
# Anon key: eyJ...
# Service role key: eyJ...
# 1. Make changes in local Studio (localhost:54323)
# 2. Generate migration from diff
supabase db diff -f <migration_name>
# 3. Review generated SQL
cat supabase/migrations/*_<migration_name>.sql
# 4. Reset to test
supabase db reset
# 1. Create empty migration
supabase migration new create_users_table
# 2. Edit the migration file
# supabase/migrations/<timestamp>_create_users_table.sql
# 3. Apply locally
supabase db reset
Use Drizzle (TypeScript) or SQLAlchemy (Python) - see framework-specific skills.
# Push to remote (staging/production)
supabase db push
# Check migration status
supabase migration list
-- 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);
-- 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');
-- 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();
-- 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;
# Public (safe for client-side)
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
# .env.local (local development)
SUPABASE_URL=http://localhost:54321
SUPABASE_ANON_KEY=<from supabase start>
DATABASE_URL=postgresql://postgres:postgres@localhost:54322/postgres
# .env.production (remote)
SUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_ANON_KEY=<from dashboard>
DATABASE_URL=<connection pooler URL>
# Transaction mode (recommended for serverless)
# Add ?pgbouncer=true to URL
DATABASE_URL=postgresql://...@pooler.supabase.com:6543/postgres?pgbouncer=true
# Session mode (for migrations, long transactions)
DATABASE_URL=postgresql://...@pooler.supabase.com:5432/postgres
supabase functions new hello-world
// 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' } }
);
});
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 }));
});
# Serve locally
supabase functions serve
# Deploy single function
supabase functions deploy hello-world
# Deploy all
supabase functions deploy
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]
);
# Lifecycle
supabase start # Start local stack
supabase stop # Stop local stack
supabase status # Show status & credentials
# 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
# Migrations
supabase migration new <name> # Create migration
supabase migration list # List migrations
supabase migration up # Apply pending (remote)
# Functions
supabase functions new <name> # Create function
supabase functions serve # Local dev
supabase functions deploy # Deploy all
# Types
supabase gen types typescript --local > types/database.ts
# Project
supabase link --project-ref <id> # Link to remote
supabase projects list # List projects
# .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 lint
deploy:
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
Weekly Installs
211
Repository
GitHub Stars
530
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
opencode172
gemini-cli162
claude-code158
codex153
cursor140
github-copilot138
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
106,200 周安装