Supabase 开源 Firebase 替代
一句话概述
Supabase 是一个基于 PostgreSQL 的开源后端平台,提供数据库、认证、存储、实时订阅、Edge Functions 等"全家桶"服务,被称为"开源 Firebase 替代品",GitHub 99K+ Star,超过 200 万开发者使用,免费层无 API 请求限制。
核心知识点表格
| 知识点 | 说明 |
|---|
| 官网 | https://supabase.com |
| 项目地址 | https://github.com/supabase/supabase |
| GitHub Stars | 99,200+ |
| 核心数据库 | PostgreSQL(业界使用率 55.6%) |
| 核心功能 | 数据库 + Auth + Storage + Realtime + Edge Functions |
| API 类型 | REST(自动生成)+ GraphQL + Realtime WebSocket |
| 向量搜索 | 内置 pgvector 扩展 |
| 许可证 | Apache 2.0 |
| 估值 | $50 亿(2025年10月) |
| 免费层 | 2 个项目,无 API 请求限制 |
安装与配置
方式一:使用 Supabase Cloud(最简单)
1. 访问 https://supabase.com 注册账号
2. 点击 "New Project" 创建项目
3. 设置项目名、数据库密码、选择区域
4. 等待约 2 分钟,项目就绪
5. 在 Settings → API 中获取:
- Project URL(如 https://xxx.supabase.co)
- anon key(公开密钥,用于客户端)
- service_role key(服务密钥,用于后端)
安装 Python 客户端
pip install supabase # 安装 Supabase Python SDK
安装 JavaScript 客户端
npm install @supabase/supabase-js # 安装 JS SDK
方式二:本地 Docker 开发
# 安装 Supabase CLI
npm install -g supabase # 全局安装 CLI
# 初始化项目
supabase init # 在当前目录创建 supabase 配置
# 启动本地 Supabase(包含所有服务)
supabase start # 启动 PostgreSQL + Auth + Storage + Realtime 等
# 启动后会显示所有服务的地址和密钥
# API URL: http://localhost:54321
# DB URL: postgresql://postgres:postgres@localhost:54322/postgres
# Studio URL: http://localhost:54323 (数据库管理界面)
基本使用
初始化客户端
from supabase import create_client # 导入 Supabase 客户端
# 初始化
url = "https://xxx.supabase.co" # 你的项目 URL
key = "eyJhbGciOiJIUzI1NiIsInR..." # 你的 anon key
supabase = create_client(url, key) # 创建客户端
数据库 CRUD 操作
# === 创建数据(INSERT) ===
result = supabase.table("papers").insert({
"title": "宏基因组分析方法综述",
"abstract": "本文综述了主要的宏基因组分析方法...",
"year": 2024,
"topic": "metagenomics"
}).execute()
print(result.data) # 插入的数据
# === 查询数据(SELECT) ===
result = supabase.table("papers") \
.select("*") \ # 选择所有列
.eq("topic", "metagenomics") \ # WHERE topic = 'metagenomics'
.gte("year", 2024) \ # AND year >= 2024
.order("year", desc=True) \ # ORDER BY year DESC
.limit(10) \ # LIMIT 10
.execute()
for paper in result.data:
print(f"{paper['title']} ({paper['year']})")
# === 更新数据(UPDATE) ===
result = supabase.table("papers") \
.update({"year": 2025}) \ # SET year = 2025
.eq("id", 1) \ # WHERE id = 1
.execute()
# === 删除数据(DELETE) ===
result = supabase.table("papers") \
.delete() \ # DELETE
.eq("id", 1) \ # WHERE id = 1
.execute()
用户认证
# 邮箱密码注册
result = supabase.auth.sign_up({
"email": "user@example.com",
"password": "securepassword123"
})
# 登录
result = supabase.auth.sign_in_with_password({
"email": "user@example.com",
"password": "securepassword123"
})
user = result.user # 用户信息
session = result.session # 会话信息(含 JWT token)
print(f"用户ID: {user.id}")
# 登出
supabase.auth.sign_out()
# OAuth 登录(Google、GitHub 等 20+ 社交登录)
result = supabase.auth.sign_in_with_oauth({
"provider": "github" # 使用 GitHub 登录
})
文件存储
# 创建存储桶
supabase.storage.create_bucket("papers", {"public": False}) # 私有桶
# 上传文件
with open("paper.pdf", "rb") as f:
supabase.storage.from_("papers").upload(
"2024/my-paper.pdf", # 存储路径
f, # 文件内容
{"content-type": "application/pdf"}
)
# 获取文件 URL
url = supabase.storage.from_("papers").get_public_url("2024/my-paper.pdf")
print(url)
# 下载文件
data = supabase.storage.from_("papers").download("2024/my-paper.pdf")
高级用法
实时订阅(Realtime)
# 监听数据库变化(实时推送)
def handle_change(payload):
"""数据变化时的回调函数"""
print(f"事件类型: {payload['eventType']}") # INSERT/UPDATE/DELETE
print(f"新数据: {payload['new']}") # 变化后的数据
print(f"旧数据: {payload['old']}") # 变化前的数据
# 订阅 papers 表的所有变化
channel = supabase.channel("papers-changes")
channel.on_postgres_changes(
event="*", # 监听所有事件
schema="public", # schema 名
table="papers", # 表名
callback=handle_change # 回调函数
).subscribe()
向量搜索(pgvector)
-- 在 Supabase SQL 编辑器中启用 pgvector
CREATE EXTENSION IF NOT EXISTS vector;
-- 创建带向量列的表
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT,
embedding vector(384)
);
-- 创建搜索函数
CREATE OR REPLACE FUNCTION match_documents(
query_embedding vector(384), -- 查询向量
match_threshold float, -- 相似度阈值
match_count int -- 返回数量
)
RETURNS TABLE (
id int,
content text,
similarity float
)
LANGUAGE sql STABLE
AS $$
SELECT
documents.id,
documents.content,
1 - (documents.embedding <=> query_embedding) AS similarity
FROM documents
WHERE 1 - (documents.embedding <=> query_embedding) > match_threshold
ORDER BY documents.embedding <=> query_embedding
LIMIT match_count;
$$;
# 在 Python 中调用向量搜索
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("all-MiniLM-L6-v2")
query_embedding = model.encode("糖尿病肠道菌群").tolist()
# 调用 Supabase RPC 函数
result = supabase.rpc("match_documents", {
"query_embedding": query_embedding,
"match_threshold": 0.7,
"match_count": 5
}).execute()
for doc in result.data:
print(f"相似度: {doc['similarity']:.4f} - {doc['content']}")
Row Level Security(行级安全)
-- RLS 让不同用户只能看到自己的数据
-- 启用 RLS
ALTER TABLE papers ENABLE ROW LEVEL SECURITY;
-- 创建策略:用户只能读取自己的数据
CREATE POLICY "Users can read own papers"
ON papers FOR SELECT
USING (auth.uid() = user_id); -- auth.uid() 返回当前登录用户的 ID
-- 创建策略:用户只能插入自己的数据
CREATE POLICY "Users can insert own papers"
ON papers FOR INSERT
WITH CHECK (auth.uid() = user_id);
Edge Functions(Serverless 函数)
# 创建 Edge Function
supabase functions new hello-world # 创建函数模板
# 编辑函数代码(TypeScript/Deno)
# supabase/functions/hello-world/index.ts
// supabase/functions/hello-world/index.ts
Deno.serve(async (req) => {
const { name } = await req.json() // 解析请求体
const data = {
message: `Hello ${name}!`, // 返回消息
}
return new Response(
JSON.stringify(data), // 返回 JSON
{ headers: { "Content-Type": "application/json" } },
)
})
# 部署函数
supabase functions deploy hello-world # 部署到 Supabase
# 调用函数
curl -X POST https://xxx.supabase.co/functions/v1/hello-world \
-H "Authorization: Bearer <anon-key>" \
-d '{"name": "World"}'
常见报错与解决
| 报错信息 | 原因 | 解决方法 |
|---|
Invalid API key | API Key 错误 | 检查 anon key 是否正确 |
RLS policy violation | 行级安全策略拒绝 | 检查 RLS 策略是否允许当前操作 |
JWT expired | 登录 token 过期 | 重新登录或刷新 token |
Relation does not exist | 表不存在 | 先在 SQL 编辑器或 Dashboard 创建表 |
Storage bucket not found | 存储桶不存在 | 先创建存储桶 |
Function invocation failed | Edge Function 报错 | 查看函数日志排查 |
速查表
# === Supabase Python SDK 速查 ===
from supabase import create_client
sb = create_client(url, key)
# 数据库
sb.table("t").select("*").execute() # 查询所有
sb.table("t").select("*").eq("col", "val").execute() # 条件查询
sb.table("t").insert({"col": "val"}).execute() # 插入
sb.table("t").update({"col": "val"}).eq("id", 1).execute() # 更新
sb.table("t").delete().eq("id", 1).execute() # 删除
# 认证
sb.auth.sign_up({"email": "...", "password": "..."})
sb.auth.sign_in_with_password({"email": "...", "password": "..."})
sb.auth.sign_out()
sb.auth.get_user()
# 存储
sb.storage.from_("bucket").upload("path", file)
sb.storage.from_("bucket").download("path")
sb.storage.from_("bucket").get_public_url("path")
# RPC(调用数据库函数)
sb.rpc("function_name", {"param": "value"}).execute()
与同类工具对比
| 特性 | Supabase | Firebase | Appwrite | PocketBase |
|---|
| 数据库 | PostgreSQL | Firestore(NoSQL) | MariaDB | SQLite |
| 开源 | Apache 2.0 | 否 | BSD-3 | MIT |
| 自托管 | 支持 | 不支持 | 支持 | 支持 |
| 向量搜索 | pgvector | 不支持 | 不支持 | 不支持 |
| SQL 支持 | 完整 SQL | NoSQL | 有限 | SQLite SQL |
| 实时 | WebSocket | 原生 | WebSocket | WebSocket |
| 免费层 | 2项目/无请求限制 | 慷慨(有每日限制) | 自托管免费 | 完全免费 |
| 社区 | 99K+ Star | 最大 | 46K+ Star | 43K+ Star |
选择建议:如果你要做正式的 Web/App 后端项目,Supabase 是性价比最高的选择——PostgreSQL 的强大 + 开源无锁定。如果只是做个人小项目/原型,PocketBase 更轻量。