Convex 源码导读:开源仓库版图、核心架构与阅读路线
8月 11, 2026
AI 参与说明(Agent:/root、/root/repo_landscape、/root/backend_architecture、/root/ecosystem_clients):本文由 Agent 根据 Convex 官方文档、官方 GitHub 仓库的 README、许可证、仓库元数据与当前源码辅助整理,重点核对仓库职责、调用边界与源码阅读入口。资料核验于 2026-08-11;本文是源码研究导读,不是对 Convex Cloud 的产品路线、服务等级或许可解释的替代。源码、文档与仓库状态会变化,请以文末一手来源和对应 commit 为准。
适用范围:本文面向已经会 TypeScript,且希望理解 Convex 为什么能同时提供数据库、事务、实时订阅与后端函数的开发者。它讨论公开可见的源码及其边界;不会把某个示例、Component 或组织内的上游 fork 误写成 Convex 核心服务。
先说结论#
如果只准备认真读一个仓库,选 get-convex/convex-backend。它不是一个狭义的“数据库 crate”,而是 Convex 的核心后端单体仓库:Rust 后端、用户函数执行环境、Dashboard、CLI/SDK 的同仓副本,以及自托管材料都在这里。真正决定 Convex 特性的核心链路是:
客户端协议与订阅
→ 后端 HTTP / WebSocket 入口
→ 应用层的函数调用、鉴权、调度与 OCC 重试
→ 用户 TypeScript 函数运行时
→ 事务数据库、读集订阅与失效通知
→ 回推新的 query 结果给客户端组织里的其他仓库并非另一套同等地位的“微服务”:它们大致分为客户端 SDK、可安装的 Convex Component、认证/AI/支付等集成、模板和演示,以及为了构建后端而镜像的上游依赖。研究源码时,最重要的策略是先沿一条完整请求链读通,再按兴趣进入 Component 或某项功能;不要按 GitHub star 数量或仓库名称逐个随机打开。
截至本文核验日,get-convex 的 GitHub 组织页显示 191 个公开仓库;其中也包含上游 fork、实验、历史项目和模板。因此下文按系统角色而不是按仓库数量罗列,避免把 191 个仓库都误当成产品运行所必需的组件。组织首页与仓库列表
1. 先划清公开源码、许可与云端边界#
Convex 官方说明自托管版本使用公开的后端代码,客户端、Dashboard 和 CLI 也公开可见;不过“能看源码”与“所有部分都是普通 Apache-2.0 开源软件”是两件不同的事。Self Hosting
convex-backend 根目录当前的 LICENSE.md 是 Functional Source License 1.1, Apache 2.0 Future License(FSL-1.1-Apache-2.0)。它允许符合许可的使用、修改与再分发,但排除了竞争性服务;每个版本在公开两年后会转为 Apache-2.0。也就是说:
| 结论 | 正确理解 |
|---|---|
| 后端源码可研究、可自托管 | 是;官方提供 Docker 与二进制方式,也提供从源码构建说明。 |
| 当前核心后端可无条件作为 Apache-2.0 竞争性托管产品使用 | 否;应以 FSL 的“Competing Use”定义和未来许可证条款为准。 |
| 所有独立仓库使用同一许可证 | 否;例如不少 SDK 和 Component 是 Apache-2.0,也有 MIT 或其他许可证,必须逐仓库检查。 |
| 读到公开后端就等于读到了完整 Convex Cloud 生产环境 | 否;官方 README 说明开源仓库通常在数日内同步内部开发,但随机化测试框架不包含在开源交付中;托管服务的运维、控制面与生产配置也不能仅靠源码推断。 |
这不是法律意见。若计划分发、改造或提供托管服务,应让项目负责人按目标 commit 的完整许可证和专业法律意见评估,而不是只看本文或 GitHub 标签。
本文分析的可复核源码快照为:convex-backend commit 5e285678… 与 convex-js commit da09ac29…。它们只是阅读坐标,不是建议锁定的生产版本。
2. 一张图建立心智模型#
Convex 的关键不是“把数据库结果推给前端”这一件事,而是把确定性的 query/mutation、事务数据库和订阅失效机制绑在同一条执行链上。官方模型中,query 只读且可订阅,mutation 在事务中读写,action 用于网络 I/O 等非确定性工作;action 要通过 query 或 mutation 间接访问数据库。Functions Convex Overview
flowchart TD
client["React、浏览器或其他客户端"] --> js["convex-js:SDK、协议、React hooks、CLI"]
js --> edge["convex-backend / local_backend:HTTP、WebSocket、认证与路由"]
edge --> sync["sync:会话、query 集合、订阅重连与增量更新"]
sync --> app["application:函数调用、鉴权、调度、缓存与 OCC 重试"]
app --> runner["function_runner / udf / isolate:执行用户函数与系统调用"]
runner --> db["database:快照、读写集、提交、订阅失效"]
db --> storage["storage、SQLite / Postgres / MySQL、文件与索引"]
db -- "写入使读集失效" --> sync
sync -- "新的 query 结果" --> edge
edge --> js这张图同时解释了三个容易混淆的概念:
- 数据库事务:mutation 的读写在一个事务中完成;冲突时系统可以重试确定性的函数。
- 实时订阅:不是客户端轮询表,而是 query 执行后形成可订阅的读集;相关写入发生后,该 query 被判为失效并重跑。
- 外部副作用:调用 LLM、Stripe 或任意
fetch的 action 不能享受 mutation 的自动事务重试,因为服务端无法知道外部请求是否已经生效。
后两点可从公开 API 约束和实现同时验证:官方文档规定 query/mutation 不做外部网络调用,action 才能调用外部服务;Rust 的 database 与 sync 源码则显式包含 transaction、subscription 和 invalidation 路径。Actions crates/database crates/sync
3. GitHub 仓库版图:哪些是核心,哪些是外围#
3.1 必须优先看的基础仓库#
| 仓库 | 角色 | 为什么值得读 | 研究优先级 |
|---|---|---|---|
convex-backend | 核心后端单体仓库 | Rust 事务/订阅/运行时实现,及同仓的 Dashboard、函数运行时、CLI/SDK 副本和自托管配置 | 最高 |
convex-js | TypeScript/JavaScript SDK 与 CLI | convex/server、convex/react、convex/browser、convex/values、Next.js 辅助代码和 convex CLI 的集中入口 | 最高 |
convex-py | Python client | 理解非 JavaScript 调用 Convex API 的客户端边界;不包含后端事务引擎 | 按语言需要 |
convex-rs | Rust client | 适合研究 Rust 应用如何调用 Convex,而不是后端本身如何实现 | 按语言需要 |
convex-mobile 与 convex-swift | 移动客户端基础 | 前者以 Rust client 的 FFI wrapper 连接 Android/iOS 库,后者是建立在 Rust client 上的 Swift client;适合从跨语言值和订阅协议理解移动端接入 | 按平台需要 |
convex-svelte、convex-react-query | 框架适配/缓存桥接 | 用于研究 Svelte/SvelteKit 或 TanStack Query 集成;不是 React 主客户端或同步引擎的实现 | 按框架需要 |
一个很有用的细节:在本文的两个源码快照中,convex-js 的文件树与 convex-backend/npm-packages/convex 完全一致(排除 Git 元数据后比对)。因此,阅读 JS 客户端/CLI 时优先打开更聚焦的 convex-js 即可;追踪发布包或完整后端构建时,回到 npm-packages/convex。当前包元数据的 repository 字段指向后者,故对“发布包的规范源码位置”采取保守解释时应以单体仓库路径为准;实际 PR 与发布流程仍可能演进。
多语言客户端不是五套彼此独立的后端协议:其中 Python、移动端和 Swift 会沿 Rust client 复用协议能力。研究跨语言值编码、订阅和移动端行为时,可按下面的依赖方向走;JavaScript 客户端则是另一条 TypeScript 实现线。
flowchart TD
rs["convex-rs:Rust 同步协议 client"] --> py["convex-py:PyO3 Python 封装"]
rs --> mobile["convex-mobile:FFI 移动端封装"]
mobile --> android["Android Kotlin library"]
mobile --> swift["convex-swift:iOS / macOS client"]3.2 官方 Component:26 个应用层积木,不是内核#
Convex 的官方 Component 清单将这一组项目明确定义为“由 Convex 团队构建的开源 Component”。截至本文核验日,它列出 26 个 TypeScript 项目;它们在应用中有独立 schema、函数、数据和隔离执行环境,除非显式传入能力,否则不能任意读取主应用数据或调用主应用函数。官方 Component 清单 Components Overview
它们很适合学习如何使用 schema、函数、调度与隔离;它们不会替代或改写 convex-backend 中的事务、订阅和函数运行时。Components 平台本身仍标为 beta/unstable,因此本文把它们当作高质量架构用例,而不是承诺长期不变的内核 API。
| 方向 | 官方 Component 仓库 | 对源码研究的价值 |
|---|---|---|
| 持久化执行与调度 | workflow、workpool、batch-worker、action-retrier、crons | 学习持久化步骤、重试、并发上限与 cron 如何建立在事务、scheduler 和 action 之上;workflow 还能作为追踪 Workpool 组合方式的入口。 |
| 数据结构与可靠性 | aggregate、sharded-counter、rate-limiter、migrations、geospatial、action-cache | 观察聚合、热点分片、事务性应用层限流、状态迁移、地理索引和缓存如何只用平台原语实现。 |
| AI 与协作体验 | agent、rag、persistent-text-streaming、presence、prosemirror-sync | 学习会话/检索、流式文本、在线状态和服务端授权协同编辑如何与实时 query 组合;它们仍是架构用例,不是底层同步协议本身。 |
| 身份、存储与外部服务 | better-auth、workos-authkit、r2、expo-push-notifications、launchdarkly、resend、twilio、stripe、polar、static-hosting | 用于研究 action、webhook、凭据、幂等性、文件边界和第三方服务集成;不要把外部厂商的运行时行为误归因于 Convex。 |
若当前目标是“理解 Convex 内核”,Component 应放在第二阶段:先读 workflow 或 agent 这类有兴趣的项目,再回到核心源码确认它使用了哪些平台原语。关于 Workflow 的实际 API、重放和幂等边界,可继续阅读站内的 Convex Workflow:接口、事件与恢复 API 实战。
3.3 辅助库、实验与应用集成:不要误标为稳定官方 Component#
convex-helpers 是补充官方包的实用模式集合;convex-auth 是部署内认证库,仍处于 beta。它们值得读,但应与上述官方 Component 清单分开。
automerge-sync、table-history、reactions 和 mastra 也是有价值的实验或辅助源码;其中有的 README 仍标为 beta、保留 TODO 或包含模板内容。读它们时应以特定 commit 的 README 和测试为准,而不应把它们升级为成熟的基础能力。
3.4 模板、演示、测试与需要降权的项目#
| 类别 | 仓库或命名模式 | 正确用途 |
|---|---|---|
| 项目脚手架与样板 | templates、template-*、convex-demos、convex-*-demo | 学习推荐的项目布局、部署配置和前端集成;不用于推断后端内部接口。 |
| 教程和示例应用 | convex-tutorial、convex-tour-chat、convex-chess、convex-saas、ai-* 等 | 用来建立用户侧心智模型或复现功能,不是稳定的 platform API 目录。 |
| 测试辅助 | convex-test | README 将其定位为 community-maintained 的 pure-JS mock;不要把它的行为当作真实后端等价实现或一致性证明。 |
| 已迁移/维护模式 | create-convex、convex-ents、convex-docs | 前者已标记为迁移到 templates,convex-ents 为 maintenance mode,convex-docs 已 archived 且当前文档源码位于 convex-backend/npm-packages/docs;阅读旧教程前先核对迁移说明。 |
| 上游 fork | tantivy、qdrant、rusty_v8、mysql_async、openidconnect-rs、rust-prometheus 等 | 只在 Cargo.toml 或特定 feature 将你带到它们时再读。它们存在于组织名下不等于 Convex 自研的业务模块。 |
这一分类也解释了为什么不能把“组织里有 191 个仓库”理解为“Convex 由 191 个服务组成”。完整、可变的清单应始终以 GitHub organization repositories 的 fork、archived、更新时间和 README 为准。
4. convex-backend 单体仓库:核心目录如何协作#
convex-backend 的根 README 已给出最重要的方向:crates/ 是 Rust;npm-packages/ 同时容纳公开和内部 TypeScript 包;local_backend/ 是构建在 Runtime 之上的应用服务;udf-runtime/ 初始化 query 和 mutation 的 JavaScript 环境;system-udfs/ 放置系统所用函数。Repository README
下面的表不是“每个 crate 的 API 参考”,而是第一次进入源码时最有价值的地图。
| 目录 | 在系统中的角色 | 建议先看什么 | 读到这里应回答的问题 |
|---|---|---|---|
crates/local_backend | 顶层二进制和应用服务入口;含 HTTP、WebSocket、Dashboard/CLI 与自托管相关路由 | src/main.rs、src/lib.rs、src/router.rs、src/subs/mod.rs | 客户端、CLI、HTTP action 与 Dashboard 分别从哪里进入后端? |
crates/application | 平台应用层:公开 API、身份/权限、模块、函数执行编排、调度、schema、日志、缓存和 OCC 重试 | src/api.rs、src/application_function_runner/mod.rs、src/lib.rs | query/mutation/action 如何被统一编排?冲突重试、定时任务和系统表在哪一层接入? |
crates/database | 事务、快照、读写集、提交、索引访问和订阅失效 | src/database.rs、src/transaction.rs、src/writes.rs、src/committer.rs、src/subscription.rs | 数据库如何选取快照、记录读写集、验证并提交,再让订阅失效? |
crates/sync | 每个连接的同步状态、query 集合、订阅复用/重连、向 socket 发送更新 | src/worker.rs、src/state.rs、src/subscription_reconnect.rs | 为什么只重跑受影响 query,而不是广播整张表?断线后如何恢复? |
crates/function_runner、crates/udf | 函数模块、执行请求、数据库 syscall 与返回值的后端侧桥接 | function_runner/src/server.rs 与 udf 的验证/调用代码 | 用户函数如何取得 ctx.db、ctx.scheduler 等能力,而不是直接连存储? |
crates/isolate、npm-packages/udf-runtime | 默认 Convex JavaScript runtime 的 isolate、全局对象、syscall 和 TypeScript 启动代码 | isolate/README.md、src/syscalls.rs、udf-runtime | TypeScript 的 query() / mutation() 定义如何落到受控的 Rust syscall? |
crates/node_executor、npm-packages/node-executor | Node.js action 的执行器桥接 | src/local.rs、src/executor.rs | Node action 与默认 runtime 在模块加载、外部依赖和执行边界上有什么不同? |
crates/storage、crates/db_connection、crates/sqlite、crates/postgres、crates/mysql | 持久化与数据库连接适配 | 先读 trait/调用点,再追某个后端 | 抽象层的事务语义和具体 SQL 存储实现如何分开? |
crates/indexing、crates/search、crates/vector | 索引、全文搜索与向量检索等功能域 | 从一次 ctx.db 查询或搜索 API 的调用点进入 | 这些能力如何影响读集、事务限制和订阅失效? |
npm-packages/dashboard、dashboard-self-hosted、system-udfs、self-hosted | 运营界面、系统函数和自托管装配 | self-hosted README、Docker 配置、对应前端包 | 什么属于可运行的自托管产品,什么是 Cloud Dashboard 的开发/控制面代码? |
crates/database/README.md 中有一张历史架构图,能帮助理解 SnapshotManager、表元数据和索引元数据;但文件本身标有 2022 日期,且“Active Transactions”“Committing Transactions”仍是 WIP。它适合用作术语索引,不能替代当前 database.rs、transaction.rs 与测试对行为的证明。database README
5. 沿一条真实链路读源码:实时 query 如何工作#
这是最能体现 Convex 设计的主线。下面的文件名和职责来自当前源码;具体类型/函数签名会随 commit 演进。
- 浏览器侧建立订阅。
convex-js的ConvexReactClient供 React hooks 使用;底层BaseConvexClient、protocol.ts和web_socket_manager.ts维护 WebSocket、请求和本地状态。官方文档也明确说明 React client 首次useQuery会创建订阅,连接断开后自动重连。Convex React - 后端接住 WebSocket。
local_backend/src/router.rs注册带 client version 的/sync路由;local_backend/src/subs/mod.rs把 socket 的收消息、发消息与SyncWorker拆成三个异步过程。先读这里,能避免把 HTTP API 和实时协议混为一谈。 - Sync worker 管理“此连接想要哪些 query”。
sync/src/worker.rs与sync/src/state.rs持有 query 状态、上一次结果和 subscription;它会复用仍有效的订阅,并对无效的 query 安排重跑。 - query 在统一快照上执行并产出读集。 application 层经
ApplicationFunctionRunner执行用户 query;数据库层的 transaction/token 表示该 query 在何时、读取了哪些文档或索引范围。官方文档保证单次 query 的数据库读取来自同一个逻辑时间点,这正是客户端能组合多个 query 而不看到撕裂状态的基础。Queries:Caching、Reactivity、Consistency - 数据库把读集变成失效通知。
database/src/subscription.rs描述并实现了订阅对 read-set 的跟踪;mutation 提交后,相关订阅收到 invalidation。它不是“把更新后的行直接推送给浏览器”,而是先判定 query 是否失效。 - 重跑、排序并回推。 Sync worker 在适当时间重跑无效 query,组装 server message,经
subs/mod.rs回到 WebSocket。客户端协议层再把结果归入本地 query set,React hook 订阅者重渲染。
可以把这个流程压缩为:
useQuery()
→ ConvexReactClient / BaseConvexClient
→ WebSocket /sync
→ SyncWorker
→ ApplicationFunctionRunner 执行确定性 query
→ Database 记录 read set 并返回 subscription token
mutation commit
→ Database 使相交 read set 的 subscription invalid
→ SyncWorker 重跑受影响 query
→ WebSocket 推送新结果
→ React 更新这也是为什么“实时”不等于“任意 action 结果自动订阅”:action 本身不属于 sync engine。要让外部结果进入响应式界面,通常由 action 经 mutation 写入数据库,再由依赖该数据的 query 失效和重跑。Calling External Services
6. mutation、OCC 与 action:不要把三种函数混为一谈#
mutation:事务语义从哪里来#
从源码入口看,application/src/api.rs 有 public/admin query、mutation、action 的分流;application/src/lib.rs 包含以 execute_with_occ_retries 命名的执行路径;database/src/database.rs 负责 transaction/commit,transaction.rs 与 writes.rs 保存读写状态。这些命名和依赖关系与官方承诺的“mutation 是事务、冲突时自动重试”相吻合。application/src/api.rs database/src/database.rs Convex Overview
读这段代码时,不必一开始弄懂所有 storage trait。先跟住四件事:
- transaction 从哪个 snapshot 开始;
- query/mutation 的 reads 与 writes 如何记录;
- commit 如何验证冲突并分配新的时间点;
- 哪一层决定重新执行用户 mutation,哪一层把已提交写入交给订阅系统。
这是一种乐观并发控制(OCC)模型:冲突发生时执行可能被重试,故 mutation 必须保持确定性,不能把不可重复的网络副作用塞进里面。它不意味着业务操作自动获得跨第三方系统的 exactly-once 保证。
action:允许副作用,也失去自动重试#
action 能 fetch,也可以运行在 Convex JavaScript environment 或 Node.js;但读写 Convex 数据时应调用 query/mutation。公开文档特别提示:action 有副作用,平台不能自动安全重试。例如一个付款 API 请求在网络超时前可能已成功,系统无法据此判断应否再次发起扣款。Actions:Error Handling
对应的源码阅读法是:先看 ApplicationFunctionRunner::run_action 周围的分支,再查 node_executor 和 default runtime 的调用。不要从源码中某个 AWS、Docker 或本地 executor 细节推断所有部署环境使用同一个基础设施;它们描述的是可选执行路径或当前实现切面。
scheduler:持久化调度,不会抹平外部副作用#
application/src/scheduled_jobs 与 model/src/scheduled_jobs/types.rs 是把 ctx.scheduler 落到后端模型的良好入口。官方语义可以帮助读源码时抓住不变量:从 mutation 调度函数与该 mutation 的其余写入是原子的;从 action 调度则不与整个 action 构成同一事务。已调度的 mutation 会在内部瞬态错误时重试并保证执行一次;已调度的 action 因可能有副作用而至多执行一次,不会由平台自动重试。Scheduled Functions
因此,常见的可靠链路是“mutation 记录业务意图并调度 action → action 调用外部服务 → mutation 写回可订阅的结果”。不要把 ctx.scheduler 当作能把 Stripe、邮件或 LLM 请求自动变成 exactly-once 的万能队列;外部系统仍需要业务幂等键、状态检查或补偿策略。
7. convex-js:外部可见协议、类型系统与开发工作流#
很多人一看到 Convex 就先读 Rust;但如果你还不知道客户端到底发了什么、何时建立订阅,先读 convex-js 更省时间。该仓库 README 将一个 npm 包拆成如下入口:
| 子路径/模块 | 角色 | 建议源码入口 |
|---|---|---|
convex/server | 定义 query、mutation、action、schema 与后端类型 | src/server |
convex/react | ConvexReactClient、hooks、React 订阅生命周期 | src/react |
convex/browser | HTTP client、通用浏览器调用能力 | src/browser |
convex/values | Convex value、validator 与序列化边界 | src/values |
convex/nextjs、react-auth0、react-clerk | 框架/身份提供商适配层 | 仓库对应顶层目录 |
convex CLI | 初始化、codegen、部署、日志、数据导入导出与本地开发 | src/cli |
特别推荐按这个顺序:src/browser/sync/protocol.ts → client.ts → web_socket_manager.ts → src/react/client.ts → src/cli/dev.ts / src/cli/lib/deploy2.ts。前四步让你建立线上数据通路,后两步再解释本地 convex/ 目录如何被 bundling、codegen 和推送。
8. 自托管与从源码构建:它验证什么,不验证什么#
如果目的是验证架构而不是立刻改代码,先用官方自托管 Docker 路线,比直接把整个 Rust workspace 编到能跑更快。自托管 README 明确列出三项要部署的服务:Convex backend、Convex Dashboard 和应用自己的前端;默认后端可使用本地 SQLite,也可配置 Postgres/MySQL 和 S3 等外部服务。self-hosted README
这里有一个重要边界:npm-packages/dashboard 的 README 将它说明为 Convex Cloud Dashboard,并依赖名为 big brain 的管理控制面以及云端 Vercel/WorkOS 等配置;自托管对应的是 dashboard-self-hosted。公开 workspace 中能看到 big_brain_client 和私有 API 类型,但没有完整 big_brain 服务实现。因此,Docker Compose 足以研究和运行自托管数据面、函数运行时和管理界面,不能据此断言完整 Convex Cloud 控制面及运营环境都能复现。
仅为取得一份可复核的源码树,可执行下面的只读式起步命令:
git clone --depth 1 https://github.com/get-convex/convex-backend.git
cd convex-backend
git rev-parse --short HEAD
# 先建立目录地图,不编译也不启动服务。
find crates -mindepth 1 -maxdepth 1 -type d | sort
find npm-packages -mindepth 1 -maxdepth 1 -type d | sort预期会看到 application、database、local_backend、sync、udf、isolate 等 Rust crate,以及 convex、dashboard、udf-runtime 等 npm 包。把输出的 commit 记在笔记中;之后讨论某个行为时,才不会把不同版本的结论混在一起。
官方 BUILD.md 给出的完整从源码构建路径需要 Rust nightly、与 .nvmrc 一致的 Node.js、pnpm/Turborepo 和 just;其 just run-local-backend 用于运行本地后端。构建成功只能证明该 commit 在你的环境能启动,不能证明它与 Convex Cloud 的容量、容灾、测试覆盖或运营配置等价。
9. 推荐的源码阅读路线#
下面的路线按“每一步都能解释一条更完整的因果链”设计。每步读完都应先写下自己的答案,再进入下一步。
| 阶段 | 文件/仓库 | 目标 | 完成标志 |
|---|---|---|---|
| 0 | convex-backend README、BUILD.md、self-hosted/README.md、LICENSE | 建立边界、版本和本地运行模型 | 能说清自托管包含什么,以及 FSL 的基本限制。 |
| 1 | convex-js 的 src/browser/sync/*、src/react/client.ts | 看懂客户端连接、订阅、请求与重连 | 能画出 useQuery 到 WebSocket 的路径。 |
| 2 | local_backend/src/router.rs、subs/mod.rs | 找到后端 /sync 和 HTTP/CLI 入口 | 能指出一个 WebSocket 消息如何进入 SyncWorker。 |
| 3 | sync/src/worker.rs、state.rs | 理解 query 集合、subscription 复用与 invalidation | 能解释为什么某次写入只影响部分订阅。 |
| 4 | application/src/api.rs、application_function_runner/mod.rs、scheduled_jobs/ | 理解函数种类、鉴权、调度和执行编排 | 能分别追踪 query、mutation、action 的分流及 scheduler 的入口。 |
| 5 | database/src/database.rs、transaction.rs、writes.rs、committer.rs、subscription.rs | 理解 OCC、commit 和实时性的共同基础 | 能解释 commit 以后为什么会触发 query 重跑。 |
| 6 | isolate、udf-runtime、node_executor | 看懂用户 TypeScript 到 syscall/运行时的边界 | 能说明默认 runtime 与 Node action 为什么不同。 |
| 7 | storage/索引/搜索/向量与一个 Component | 结合一个真实 feature 回读内核 | 能分辨 feature 代码、平台原语和外部集成。 |
如果你的研究问题更具体,可以从下列岔路进入:
- 想理解“实时一致 UI”:优先阶段 1、2、3、5。
- 想理解事务和冲突:优先阶段 4、5,再回看 query/mutation 的确定性约束。
- 想研究 TypeScript API、codegen 或 CLI:优先
convex-js,不要先下钻 Rust。 - 想部署自己的实例:优先
self-hosted、local_backend和 storage 配置;先用 Docker 验证,再决定是否编译源码。 - 想做认证、AI Agent、工作流或支付:先读相应 Component,再用本路线定位其依赖的平台原语。
10. 研究时最容易犯的四个错误#
- 把 Component 当内核。
workflow、agent、rate-limiter很有价值,但它们是使用 Convex 原语的应用层实现;它们无法替代database + sync + UDF runtime。 - 把 WebSocket 当成全部实时逻辑。 socket 只负责传输;核心在 query 读集、subscription invalidation 与重跑。只读前端 reconnect 代码会漏掉一致性的来源。
- 把 mutation 的自动重试推广给 action。 action 的外部副作用必须做幂等键、去重或补偿设计;不要因为 action 也叫“后端函数”就假设事务语义相同。
- 把组织内 fork 和实验项目当平台承诺。 先看
fork、archived、README、许可证、release 和近期提交,再决定一个仓库是否值得依赖或深入阅读。
结语#
Convex 的源码价值不在于“它把许多后端能力放进一个产品”,而在于它把一组相互约束的机制放进同一条可追踪的链路:确定性函数让事务可重试,事务读集让订阅可判定失效,失效后的 query 重跑再通过长连接形成一致的实时视图。
因此,最有效的研究方式不是把仓库逐个读完,而是先完成一次 useQuery → SyncWorker → query → read set → mutation commit → invalidation → UI update 的端到端追踪。读通它以后,CLI、Dashboard、搜索、Node action 和各类 Component 都会有清楚的归属。