单项目深读

Supabase:以 Postgres 为底座,把向量检索做进业务数据库

Supabase 把 Postgres、认证、存储、Realtime 和向量嵌入打包成开箱即用的平台,靠 pgvector 让 AI 应用直接在业务数据上做语义检索,Apache-

|INS-0026

大多数团队做 RAG,第一步就分裂成两套系统:业务数据在 Postgres 里,向量在另一个专门的向量库里,两边靠定时任务或双写同步。Supabase 的判断是,这一步不该存在——向量就该和业务数据待在同一个数据库里,用同一套权限、同一个事务、同一条 SQL 查询。

这个判断的落点是 pgvector。它出现在 Supabase 的 topics 列表里,和 postgres、postgrest、realtime、auth、embeddings、vectors 并列。这不是营销词的堆叠,而是它架构取向的直白描述:向量检索不是一个独立产品,而是 Postgres 的一个扩展能力。

它不是一个应用,是一组服务的编排

README 里有一句话把定位说得很清楚:Supabase 是「a combination of open source tools」,用企业级开源产品去重建 Firebase 的功能。它不追求与 Firebase 一一对应,目标是给开发者一个 Firebase 式的开发体验,但底座是开源工具。

这意味着 Supabase 本身更接近一个编排层 + 控制台,真正的能力由下面这些组件提供。README 的架构段落逐个点名了它们:

  • Postgres:对象关系数据库,30 多年持续开发,是整套系统的事实中心。所有其他组件要么读写它,要么以它为权限来源。
  • Realtime:Elixir 服务,通过 websocket 让客户端监听 Postgres 的 insert / update / delete。它轮询 Postgres 内建的复制能力拿到变更,转成 JSON,再广播给已授权的客户端。
  • PostgREST:把 PostgreSQL 数据库直接变成一个 RESTful API 的 web 服务器。
  • GoTrue:基于 JWT 的认证 API,负责注册、登录和会话管理。
  • Storage:管理 S3 上文件的 RESTful API,权限由 Postgres 处理。
  • pg_graphql:一个 PostgreSQL 扩展,对外暴露 GraphQL API。
  • postgres-meta:管理 Postgres 的 RESTful API,可以取表、加角色、跑查询。
  • Envoy:云原生的边缘与服务代理,横在前面做流量入口。

按职责分层,大致是这样:

层组件职责
数据与扩展层Postgres、pg_graphql、pgvector存储业务数据与向量,扩展出 GraphQL 与向量检索能力
API 暴露层PostgREST、Storage、postgres-meta把库、文件、元数据分别暴露成 REST 接口
认证与实时层GoTrue、RealtimeJWT 认证会话;基于复制日志的变更广播
边缘入口层Envoy统一入口、代理与流量治理
控制面Dashboard面向开发者的管理界面
客户端层supabase-js 及各语言 SDK把上述能力封装成一套调用

数据流的方向是单向的:请求经 Envoy 进入,落到对应的 API 服务;API 服务读写 Postgres;Postgres 的变更被 Realtime 捕获后反向推给客户端。认证信息(JWT)贯穿各层,Storage 的权限判断最终也回到 Postgres——这一点很关键,它意味着权限模型只有一套,不是每个子系统各管一摊。

客户端是模块化的,不是一个胖 SDK

README 对客户端库的说明值得单独拎出来:每个子库都是针对单一外部系统的独立实现。这是它「支持既有工具」的方式——不把 PostgREST、GoTrue、Realtime、Storage 揉成一个黑盒,而是让每一块都能被单独替换或单独使用。

官方维护的语言覆盖 JavaScript/TypeScript、Flutter、Swift、Python;社区维护的覆盖 C#、Go、Java、Kotlin 等。以 JS 为例,supabase-js 之下拆成 postgrest-js、auth-js、realtime-js、storage-js、functions-js 五个 feature-client。Flutter、Swift、Python 也是同样的拆分方式。

这个设计对使用者的实际影响是:你可以在一个项目里只用 auth-js 做登录,数据库访问走自己的 ORM;也可以只用 postgrest-js 调 REST,认证交给别的方案。平台的边界是可裁剪的,不是一个全有或全无的绑定。

三种运行形态,同一个底座

README 明确写了三条路径:托管平台(注册即用,什么都不用装)、自托管、本地开发。三者的组件构成一致,差别只在谁来运维。对评估者来说,这意味着不存在「先用托管、规模上来再迁移」时的架构断层——自托管的组件清单就是托管版的组件清单。

安装与上手,官方文档的入口是 supabase.com/docs,本地开发的指引在 supabase.com/docs/guides/local-development,自托管在 supabase.com/docs/guides/hosting/overview。README 本身没有给出一段可复制的 quickstart 代码,所以这里不虚构命令;能确定的是客户端侧的调用形态——以 JS 为例,初始化后按能力分域调用:

ts
import { createClient } from '@supabase/supabase-js' const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY) // 数据库(走 PostgREST) const { data, error } = await supabase .from('documents') .select('id, content') // 认证(走 GoTrue) await supabase.auth.signInWithPassword({ email, password }) // 实时订阅(走 Realtime) supabase .channel('documents') .on('postgres_changes', { event: '*', schema: 'public', table: 'documents' }, handler) .subscribe() // 文件存储(走 Storage) await supabase.storage.from('avatars').upload(path, file)

四段调用,背后是四个独立服务,但对开发者是一个 client 对象。这就是 README 说的「Firebase-like developer experience」的具体形态。

向量检索为什么落在 Postgres 里

回到开头那个分裂问题。Supabase 的 AI 能力被列为「AI + Vector/Embeddings Toolkit」,文档在 supabase.com/docs/guides/ai。它没有另起一个向量数据库产品,而是把向量作为 Postgres 里的一种列类型来处理。

这个选择带来的结构性差异,和同主题的几个项目对比最清楚:

项目定位向量检索在哪业务数据在哪
SupabasePostgres 开发平台Postgres 内(pgvector)同一个 Postgres
turbovecRust 编写的向量索引,带 Python 绑定独立索引结构(TurboQuant)不在其职责内
txtaiPython 的 all-in-one AI 框架框架内的嵌入 + 索引流水线不在其职责内
FlagEmbedding文本嵌入模型与 SDK只产出向量,不负责存储检索不在其职责内
Chinese-Word-Vectors预训练中文词向量集合不涉及不涉及

这张表的读法是:turbovec、txtai、FlagEmbedding、Chinese-Word-Vectors 都在解决「向量怎么来、怎么快速找近邻」这一段,它们是检索链路上的专用件。Supabase 解决的是另一段——向量生成之后,它和业务记录怎么共存。用 FlagEmbedding 生成 embedding、用 turbovec 建索引,你仍然需要一套东西来存用户、订单、权限,并且保证「这条向量属于哪个用户」的过滤条件在检索时生效。Supabase 的答案是:这些本来就是同一张表里的事。

过滤条件这一点是向量库方案的真实成本所在。业务检索很少是纯近邻——通常带着租户、权限、状态、时间范围的约束。当向量和业务字段在同一张表、同一个查询计划里,约束就是普通的 SQL WHERE;当它们分居两处,就得先检索再回表过滤,或者维护冗余的过滤字段。Supabase 把这个问题消解在数据模型层,而不是在应用层打补丁。

和 InsForge 的差异:为谁而建

对照列表里 InsForge 的定位最接近:同样是 TypeScript、同样是一体化后端,同样打包数据库、auth、storage。差别在服务对象——InsForge 明确面向 agentic coding,让 coding agent 端到端交付全栈应用,还额外提供 compute、hosting 和 AI gateway。

Supabase 的 README 里没有出现 agent 这个词。它的叙事对象始终是开发者:Dashboard、文档、社区论坛、Discord、按用途分流的支持渠道(建站与最佳实践去 Discussions,bug 去 Issues,数据库与基础设施问题走邮件支持)。这是一个为人设计的产品界面,而不是为 agent 设计的工具接口。两者会在一体化后端这个交叉点上相遇,但一个把「人写代码」当默认前提,一个把「agent 写代码」当默认前提。

规模与许可说明了什么

仓库的权威数字:111699 stars、17070 forks、1154 个 open issues,Apache-2.0 许可,主语言 TypeScript,创建于 2019 年 10 月,最近一次推送在 2026 年 10 月。

Apache-2.0 这个许可和 README 里那句选型原则是自洽的:「如果工具和社区已经存在,且是 MIT、Apache 2 或同等开放许可,我们就使用并支持它;如果不存在,我们就自己构建并开源。」Postgres、PostgREST、Envoy 是前者,GoTrue、Realtime、Storage、postgres-meta、pg_graphql 是后者。这条原则解释了为什么这个仓库的主语言是 TypeScript——它承载的是控制台、SDK 和胶水层,而不是数据库内核。

对选型的人来说,这个组合的实际含义是:核心能力没有一家公司的黑盒锁定,最坏情况下你可以按 README 列出的组件清单自己拼一套。代价也在这里——八个组件、一个代理、多语言 SDK 矩阵,自托管的运维复杂度是真实存在的,README 把它归到「hosting」文档而不是轻描淡写地带过,本身就是一种诚实。

源码在 github.com/supabase/supabase,官网在 supabase.com。想验证它是否适合你的场景,最有信息量的一步不是读功能列表,而是问自己:我的检索请求里,有多少约束是业务字段带来的?如果答案是「很多」,那把向量放进业务数据库就不是一个便利性选择,而是一个正确性问题。