全部文章

指南 / 2026-09-24

TanStack Start 还是 Next.js:我们为什么用 TanStack Start 做 SaaS 模板

做 React SaaS,Next.js 是默认答案。ShipKit 还是选了 TanStack Start:原生跑在 Cloudflare Workers 上、路由全程类型安全、数据流清楚到 AI 也能跟得上。这篇讲清楚这笔交换,包括我们放弃了什么。

TanStack Start 还是 Next.js:我们为什么用 TanStack Start 做 SaaS 模板

"用哪个 React 框架做 SaaS?"默认答案是 Next.js,理由也很充分:生态最大、教程最多、最好招人。我们做 ShipKit 的时候还是选了 TanStack Start。这篇文章讲为什么,也同样具体地讲这个选择的代价。如果你需要的恰好在另一边,那 Next.js 就是你的正确答案,我们希望你在买任何东西之前就知道这一点。

先交代现状:截至 2026 年 9 月,TanStack Start 处于 Release Candidate 阶段,官方文档称其功能完整、API 稳定;React Server Components 是实验性功能。这一点很重要,后面会再说。

1. 原生跑在 Cloudflare Workers 上

ShipKit 跑在 Cloudflare Workers 上,数据库用 D1,文件存 R2(为什么这么选,另一篇专门讲)。这个决定对框架选择的约束比什么都大。

TanStack Start 用 Vite 构建,Cloudflare 官方的框架指南就是用 Cloudflare Vite 插件来配置它。开发时,vite dev 把服务端代码跑在 workerd 里,也就是和生产环境相同的运行时;D1 和 R2 的绑定在本地也是真实可用的,背后是本地状态。你在自己电脑上跑通的代码,遵守的就是它上线后要遵守的那套规则。

Next.js 要经过一层适配才能跑在 Workers 上。Cloudflare 文档目前推荐用 vinext 作为在 Workers 上运行 Next.js 的默认方式,OpenNext 作为已有应用的备选。vinext 标注为 beta,图片优化等部分功能只是部分支持。它能用,也在持续变好,但本质上是把一个为 Node 和 Vercel 设计的框架翻译到另一个运行时上。一旦线上行为和 next dev 里不一样,这层翻译就是又一个要排查的地方。

2. 路由从头到尾类型安全

在 TanStack Start 里,路由器知道每一条路由、它的路径参数和查询参数,路由还可以用 schema 校验自己的查询参数。链接到一个不存在的路由、少传一个参数、查询参数类型不对,都是类型错误,不会拖到运行时才发现。

这听起来只是锦上添花,直到你在一个有四十个页面的代码库里给某个路由改名。在 ShipKit 里,这时 tsc 会把所有需要改的链接、跳转和 loader 一个个列出来。

当代码由 AI 来写时,这一点更重要。AI 会很自信地链接到上周已经改了名的路由;有了类型化的路由,这个错误在任何人看到之前,就会让 bun run typecheck 失败。

3. 读得懂的数据流

ShipKit 对数据只有一条规则,TanStack Start 让这条规则很容易遵守:

  • 路由的 loader 向 TanStack Query 要数据(ensureQueryData)。
  • query 调用一个服务端函数:带类型的 RPC,用中间件处理登录态和权限。
  • 服务端函数调用 Drizzle。

每一步都是一次函数调用,用"跳转到定义"就能一路跟下去。缓存只在一个地方:TanStack Query,默认值由你自己设。

Next.js 的 App Router 是围绕 React Server Components 设计的:数据获取发生在服务端渲染的组件里,还有好几层缓存,而且这些缓存的默认行为在大版本之间改过。这是一个很强大的模型,也有很多团队喜欢它。对我们来说,它意味着更多隐式行为。我们的检验标准是:"一个新人,或者一个 AI,只靠读代码,能不能说清楚这份数据从哪来、什么时候刷新?"显式的写法更容易通过这个检验。

4. 带中间件的服务端函数

TanStack Start 的服务端函数由校验器和处理函数组成,并且可以叠加中间件。ShipKit 有两个基础:

  • authedFn 检查是否已登录。
  • adminFn 在此之上还要求有进入后台的权限。

每个后台函数还要再声明自己需要的具体权限。因为这些都是普通的、带类型的函数,单元测试可以扫描它们:ShipKit 有一个测试,只要有任何一个后台服务端函数漏了权限检查,测试就会失败,CI 也就过不去。这条规则也写在 CLAUDE.md 里,但真正让它一直成立的是那个测试。

我们放弃了什么

这些代价是真实的,请认真掂量。

  • 生态和招人。 Next.js 的教程、示例、Stack Overflow 答案和会用它的开发者都多得多。用 TanStack Start,你会更常去读源码。
  • 成熟度。 "Release Candidate"不等于"1.0"。我们锁定精确版本、有计划地升级,ShipKit 的发布说明会写明哪次升级需要你动手。
  • React Server Components。 在 TanStack Start 里还是实验性功能。如果你的架构依赖 RSC,目前 Next.js 是更成熟的选择。
  • 开箱即用的配件。 Next.js 自带 next/image 图片优化这类功能;用 Start 要自己挑工具,而且在 Workers 上,有些只支持 Node 的包根本跑不起来。
  • 一些坑。 路由文件里只有 component 会被拆成单独的代码块,其余选项(loader、validateSearch 等)都会进主包;把 createServerFn 包进一个工厂函数,可能会把服务端模块打进浏览器端的包里。这些坑我们都踩过、修过,并且一条条写进了 CLAUDE.md,让你和你的 AI 不用再踩一遍。

什么时候该选 Next.js

选 Next.js,如果:

  • 你要部署到 Vercel,希望平台和框架出自同一家公司;
  • 你的团队已经熟悉 Next.js,或者需要按 Next.js 招人;
  • 你现在就要在生产环境用 React Server Components;
  • 你依赖的库或示例默认就是 Next.js。

选 TanStack Start,如果:

  • 你想用 Cloudflare Workers,而且中间不隔一层适配;
  • 你看重能抓出错误链接和参数的类型检查;
  • 你喜欢能一路追下去的数据流;
  • 你要和 AI 一起开发,而上面这些都会让 AI 少犯错。

ShipKit 的位置

ShipKit 从上到下都是 TanStack Start + Cloudflare Workers。登录、Stripe 和 Creem 支付、后台管理、国际化和文档都已经接好,还有防止 AI 把它们改坏的规则和测试。如果这正是你想要的技术栈,来看看,或者先打开在线演示;如果不是,我们的 TanStack Start 模板对比里也收录了基于 Postgres 和 Vercel 的模板。

更多文章