Supabase 是一款开源的 Firebase 替代方案,提供 PostgreSQL 数据库、认证、存储、实时订阅、Edge Functions 等完整后端能力。与 Firebase 不同,Supabase 基于 PostgreSQL,你可以使用标准 SQL,且可以自托管。
核心功能#
| 功能 | 说明 |
|---|---|
| Database | 托管的 PostgreSQL 数据库 |
| Auth | 用户认证(邮箱、OAuth、Magic Link) |
| Storage | 文件存储(类似 S3) |
| Realtime | 数据库变更实时推送 |
| Edge Functions | Serverless 函数(Deno 运行时) |
| AI & Vectors | 向量存储和 AI 集成 |
快速开始#
1. 创建项目#
- 访问 supabase.com
- 使用 GitHub 登录
- 点击「New Project」
- 填写项目名称和数据库密码
- 选择区域(推荐新加坡)
2. 获取连接信息#
项目设置 → API:
Project URL: https://xxx.supabase.coanon key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...service_role key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...3. 安装 SDK#
npm install @supabase/supabase-js4. 初始化客户端#
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://xxx.supabase.co', 'your-anon-key')数据库操作#
创建表#
使用 Table Editor 或 SQL Editor:
CREATE TABLE posts ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, title TEXT NOT NULL, content TEXT, author_id UUID REFERENCES auth.users(id), created_at TIMESTAMPTZ DEFAULT NOW());启用 RLS#
Row Level Security(行级安全)是 Supabase 的核心安全机制:
-- 启用 RLSALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- 允许所有人读取CREATE POLICY "公开读取" ON posts FOR SELECT USING (true);
-- 只允许作者编辑CREATE POLICY "作者编辑" ON posts FOR UPDATE USING (auth.uid() = author_id);CRUD 操作#
查询:
// 查询所有const { data, error } = await supabase.from('posts').select('*')
// 条件查询const { data } = await supabase .from('posts') .select('*') .eq('author_id', userId) .order('created_at', { ascending: false }) .limit(10)
// 关联查询const { data } = await supabase.from('posts').select(` *, author:users(name, avatar) `)插入:
const { data, error } = await supabase .from('posts') .insert({ title: 'Hello', content: 'World' }) .select()更新:
const { data, error } = await supabase .from('posts') .update({ title: 'Updated' }) .eq('id', postId) .select()删除:
const { error } = await supabase.from('posts').delete().eq('id', postId)用户认证#
邮箱注册登录#
// 注册const { data, error } = await supabase.auth.signUp({ email: 'user@example.com', password: 'password123',})
// 登录const { data, error } = await supabase.auth.signInWithPassword({ email: 'user@example.com', password: 'password123',})
// 登出await supabase.auth.signOut()OAuth 登录#
// GitHub 登录const { data, error } = await supabase.auth.signInWithOAuth({ provider: 'github', options: { redirectTo: 'https://your-app.com/callback', },})
// Google 登录const { data, error } = await supabase.auth.signInWithOAuth({ provider: 'google',})监听认证状态#
supabase.auth.onAuthStateChange((event, session) => { if (event === 'SIGNED_IN') { console.log('用户已登录', session.user) } if (event === 'SIGNED_OUT') { console.log('用户已登出') }})获取当前用户#
const { data: { user },} = await supabase.auth.getUser()文件存储#
创建存储桶#
Storage → New Bucket → 设置名称和权限上传文件#
const file = event.target.files[0]
const { data, error } = await supabase.storage .from('avatars') .upload(`${userId}/avatar.png`, file, { cacheControl: '3600', upsert: true, })获取公开 URL#
const { data } = supabase.storage .from('avatars') .getPublicUrl('path/to/file.png')
console.log(data.publicUrl)下载文件#
const { data, error } = await supabase.storage .from('documents') .download('path/to/file.pdf')存储策略#
配置 RLS 控制文件访问:
-- 允许用户上传到自己的文件夹CREATE POLICY "用户上传" ON storage.objects FOR INSERT WITH CHECK ( bucket_id = 'avatars' AND auth.uid()::text = (storage.foldername(name))[1] );实时订阅#
监听表变化#
const channel = supabase .channel('posts-changes') .on( 'postgres_changes', { event: '*', schema: 'public', table: 'posts' }, (payload) => { console.log('变化:', payload) } ) .subscribe()
// 取消订阅channel.unsubscribe()监听特定事件#
// 只监听插入.on('postgres_changes', { event: 'INSERT', ... })
// 只监听更新.on('postgres_changes', { event: 'UPDATE', ... })
// 只监听删除.on('postgres_changes', { event: 'DELETE', ... })广播消息#
// 发送const channel = supabase.channel('room-1')channel.send({ type: 'broadcast', event: 'message', payload: { text: 'Hello!' },})
// 接收channel.on('broadcast', { event: 'message' }, (payload) => { console.log(payload)})Edge Functions#
创建函数#
# 安装 Supabase CLInpm install -g supabase
# 初始化supabase init
# 创建函数supabase functions new hello-world函数代码#
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' }, })})部署#
supabase functions deploy hello-world调用#
const { data, error } = await supabase.functions.invoke('hello-world', { body: { name: 'World' },})与框架集成#
Next.js#
npm install @supabase/ssrimport { createServerClient } from '@supabase/ssr'import { cookies } from 'next/headers'
export function createClient() { const cookieStore = cookies()
return createServerClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, { cookies: { get(name: string) { return cookieStore.get(name)?.value }, }, } )}React#
// 使用 Context 提供 Supabase 客户端import { createContext, useContext } from 'react'
const SupabaseContext = createContext(supabase)
export function useSupabase() { return useContext(SupabaseContext)}自托管#
Supabase 完全开源,可自托管:
# 克隆仓库git clone https://github.com/supabase/supabasecd supabase/docker
# 配置环境变量cp .env.example .env
# 启动服务docker compose up -d定价#
| 计划 | 价格 | 特点 |
|---|---|---|
| Free | $0/月 | 500MB 数据库,1GB 存储 |
| Pro | $25/月 | 8GB 数据库,100GB 存储 |
| Team | $599/月 | 无限项目,优先支持 |
免费计划足够个人项目使用。
Supabase vs Firebase#
| 特性 | Supabase | Firebase |
|---|---|---|
| 数据库 | PostgreSQL | NoSQL |
| 查询语言 | SQL | 专有 API |
| 开源 | ✅ | ❌ |
| 自托管 | ✅ | ❌ |
| 实时订阅 | ✅ | ✅ |
| 定价模式 | 按资源 | 按使用量 |
选择建议:
- 需要关系型数据库 → Supabase
- 需要自托管/开源 → Supabase
- 移动端为主 → Firebase
- 完全 Serverless → Firebase
最佳实践#
1. 始终启用 RLS#
ALTER TABLE your_table ENABLE ROW LEVEL SECURITY;2. 使用 TypeScript 类型#
npx supabase gen types typescript --project-id your-project > types/supabase.tsimport { Database } from './types/supabase'
const supabase = createClient<Database>(url, key)3. 环境变量安全#
# 客户端使用 anon keyNEXT_PUBLIC_SUPABASE_ANON_KEY=...
# 服务端使用 service_role keySUPABASE_SERVICE_ROLE_KEY=...