副业上线第 40 天,我关掉了 Firebase 的付费计划。账单从每月 25 美元降到了 0 美元。但这不是省钱的故事,是一个关于"我以为迁移半天,结果折腾 30 天"的实录。如果你正打算从 Firebase 跳到 Supabase,或者正在选型 BaaS,这篇给你省下至少 2000 块钱的咨询费和 15 个失眠夜。
为什么我从 Firebase 叛逃
我的副业是一个小团队协作工具,日活峰值 300 人。Firebase 的前 6 个月一切正常,直到第 5 个月账单突然从预估的 20 美元跳到 47 美元。查了明细,是 Firestore 的读操作爆了——我写了个低效的监听器,某个集合每次变更拉了全量数据。
Firebase 的罪状不是贵,是你无法预判它什么时候会贵。
说实话,Firebase 的 Auth 和 Realtime Database 确实是行业标杆,但它的 Firestore 查询能力太弱了——不支持数组的 contains 过滤、JOIN 得自己写、聚合函数是摆设。我甚至为了一个"统计今日新增任务数"的 API,不得不引入一个小型 Worker 定时写计数表。
我们团队最后做了一次技术评估,列了几个痛点:
- Firestore 的索引限制导致复杂查询经常要手动建索引,联表查询写起来像在受刑
- 实时监听 1 个文档的变更,如果文档内有数组字段,整个数组都会推送,流量浪费 3 倍
- Firebase 的免费层 Spark 计划在 2023 年后就不再给新项目提供 Cloud Functions 免费额度了,老项目也被迫在 2024 年 9 月后迁移到 Blaze 计划
回头看,那 47 美元的账单里至少有 30 美元是在为设计失误买单。
迁移决策:我对比了 4 个 BaaS 方案
Day 1 我列了张对比表,把 Firebase、Supabase、Supabase 的竞品 Appwrite、还有直接用 Node.js + PostgreSQL 自建,四条路都过了一遍。
| 方案 | 数据库类型 | 实时能力 | 认证成本 | 免费层额度 | 100 人日活预估月成本 | 查询复杂度 |
|---|---|---|---|---|---|---|
| Firebase Firestore | 文档型 | 原生实时 | 内置 | 50K 读/天 | 25-47 美元 | 低-限制多 |
| Supabase | 关系型 (PostgreSQL) | 原生实时 | 内置 + 自建 | 500MB 数据库, 2 个免费项目 | 0-25 美元 | 高-SQL 随心 |
| Appwrite | 关系型 (MariaDB) | 有限 | 内置 | 有限 | 15-30 美元 | 中-API 限制 |
| 自建 Node+PG | 关系型 | 需要自研 WS | 自研 | 服务器 5 美元起 | 5-20 美元 | 最高 |
我当时选了 Supabase。核心原因就一条:我的业务里有一个"项目-任务-标签"的多对多模型,Firestore 里我写了 200 多行的云函数来处理联表逻辑,而这些在 PostgreSQL 里就是一条 JOIN 加 ARRAY_AGG 的事。
另一个隐性优势是 Supabase 直接给你一个 PostgreSQL 实例,这意味着你可以直接用 pg_dump 做备份,用 pgAdmin 查数据,用任何你熟悉的关系型数据库工具链。这个自由度在 Firebase 上是不存在的。
真实踩坑 1:RLS 策略让我第一天就差点回滚
Day 2 晚上,我把 schema 建好,写了几个简单的 RLS(Row Level Security)策略,然后测试登录。
现象:用户 A 能读到用户 B 的私有任务。
困惑:我的 RLS 策略明明写了 auth.uid() = user_id 啊,为什么没生效?
解法:查了两小时后发现,我在 Supabase Dashboard 里手动插入测试数据时用的是服务角色密钥,它默认绕过 RLS。而我用客户端 SDK 查询时,没注意 Supabase 的 JS 客户端默认不发送 Authorization 头——需要在初始化时显式传入 global.headers 或者用 supabase.auth.getSession() 后的 token。
真实情况是这个 SDK 的默认行为让 90% 的新用户在第一天掉坑。正确做法是:
const supabase = createClient(url, anonKey, {
global: {
headers: {
Authorization: `Bearer ${session.access_token}`
}
}
})
或者更靠谱的做法——用 supabase.auth.onAuthStateChange 监听 token 变化,然后 supabase.setAuth(token)。这个 API 在 2.0 版本后一直存在,但文档里只在 Authentication 页面的一个角落提到。
血泪教训:RLS 不是写出来就生效的,你要在 SQL 编辑器里直接执行 select * from your_table 测试,且要分别用 anon 角色和 authenticated 角色跑一遍。
真实踩坑 2:Edge Functions 的超时限制卡死了我的文件上传
第 2 周,我需要做一个 PDF 预览功能。Firebase 时代我用 Cloud Functions,可以配置最长 540 秒的执行时间。Supabase 的 Edge Functions 默认超时时间是 10 秒,而且不支持配置——对,你没看错,目前 2024 年的版本依然不支持。
现象:上传 20MB 的 PDF,转成图片预览的过程中,Edge Function 直接抛 Worker terminated 异常。
解法:我用了 3 天时间,最终方案是把文件预处理拆成两步:
- 客户端用 pdf.js 先渲染第一页,直接上传图片预览图
- 全量 PDF 传完后,由一个独立的小 Worker(部署在 Vercel)在后台处理
这直接导致我不需要 Edge Functions 做重型计算了。说实话,这个决策让我的架构更健康了,但 Supabase 官方如果真想在 BaaS 里和 Firebase Functions 对打,光靠 10 秒超时是不够的。
另外一个坑:Edge Functions 的日志查询界面极其简陋,只能按 Request ID 查,不能按时间范围过滤。我花了 1 小时排查一个 bug,最后发现是环境变量没配上——但 Dashboard 里看不出环境变量是否生效,只能 console.log 打出来。
真实踩坑 3:PostgreSQL 的全文索引把我按在地上摩擦
第 3 周,我加了个搜索功能。Firebase 时代我用的是 Algolia 外部搜索(SaaS 月付 19 美元)。迁到 Supabase 后,我想省点钱,直接用 PostgreSQL 的 tsvector 和 GIN 索引。
现象:搜索"项目进度",返回结果里"进度"能匹配但"项目"匹配不到,或者顺序完全诡异。搜索"任务完成"时,一个包含"任务未完成"的记录排名比完全匹配"任务完成"的记录还靠前。
解法:我花了两个晚上才明白关键问题——PostgreSQL 默认的 textsearch_configuration 是 simple,它只做空格分词,不懂中文词边界。中文分词需要 zhparser 或 pg_jieba 这类扩展,而 Supabase 的托管实例不提供这些扩展。
最终我选择了用 ts_zh 的替代方案:在插入时手动把分词后的结果存到一个 tsvector 列,并指定 simple 配置配合 zhparser 不行就降级了——我改成了提前在应用层用 jieba 库分词,然后把分词结果用空格拼接,存储到 tsvector 列。
这带来一个新的痛点:每次插入或更新都要手动更新 tsvector 列,写触发器成了新的麻烦。而 Firebase 时代我用第三方搜索,虽然花钱但 0 维护。
第 4 周:性能数据与成本统计
第 4 周我把完整数据跑了一遍,用 k6 做了压力测试。100 个并发用户模拟真实操作,结果对比:
- Supabase 的 API 平均响应时间 230ms,Firebase 平均 180ms,差异 20% 左右
- 但 Supabase 的数据库查询响应时间 95% 在 80ms 以下,Firebase Firestore 的 95% 响应时间在 300ms 左右
- 30 天账单:Supabase 完全 0 美元(免费层),Firebase 最后一个月 47 美元
- 迁移花了 30 天,其中 25 天在写 SQL 迁移脚本和修 RLS,只有 5 天在写新功能
我额外测了一件事:Realtime 订阅的延迟。Supabase 的平均推送延迟 40ms,Firebase 是 20ms。如果你做的是多人协作编辑器,这个差距可能值得你多付 25 美元。但我的场景是任务提醒+评论通知,40ms 感知不到。
复盘:Supabase 赢在哪里,输在哪里
我们团队最后留下的总结是:
- SQL 能力救了命,复杂查询从 200 行云函数变成 3 行 JOIN
- 免费层真的能跑,500MB 数据库对 300 日活用户完全够用
- 迁移工具链很成熟,
supabase db dump和db push命令比 firebase CLI 好用 2 倍 - 社区和文档的完整度在 2024 年已经追上 Firebase 了,官方 Discord 响应速度平均 30 分钟
但我也要承认 Supabase 不如 Firebase 的地方,这里必须说清楚:
- 认证系统不完善:Supabase 的 Auth 在 2024 年 5 月才支持多租户 SSO,而 Firebase Auth 从 2019 年就有了。我的副业有个场景需要接入企业微信 OAuth,Firebase 有现成扩展,Supabase 我不得不自己写了一个小服务做代理。
- Edge Functions 的稳定性与函数编排完全比不上 Firebase Functions 的 PubSub 触发器和调度器。我有个定时清洗数据的任务,Supabase 只能用 PG Cron(在数据库内执行),而 Firebase 的 Cloud Scheduler 配置起来更直观。
- 客户端 SDK 的质量:Supabase 的 JS SDK 在 2.0 版本后稳定多了,但实时订阅的断线重连逻辑依然不如 Firebase 干净。有一次我开了 3 个标签页,订阅同一文档,收到了 3 次重复推送。
最后给你一个决策框架
如果你的业务是重关系型数据(多对多、复杂聚合、事务),直接选 Supabase。如果你的业务是重实时协作(棋盘、共享光标、多人画布),Firebase 依然更成熟。
如果你像我一样想省钱,Supabase 的免费层真的能撑到 5000 日活——我压测过,在 500 并发下响应时间才从 80ms 升到 240ms。
如果给你一次重来的机会,你会为了 47 美元的账单,搭上 25 天的迁移时间吗?