2026 年,我为什么放弃 Next.js 改用 TanStack Start
记录我的技术架构,从 Next.js 到 TanStack Start 的渐进式技术选型
2026 年,我为什么放弃 Next.js 改用 TanStack Start
这次技术选型不追新,也不堆技术栈,只解决一个更实际的问题:
一个个人开发者,如何长期维护一套开发体验好、部署简单、未来能支持多端的全栈技术方案?
过去我们习惯默认选择 Next.js。它成熟、生态大、模板多、AI 也很熟。但在实际独立开发中,Next.js 也暴露出一些明显问题:
开发体验变重
热重载速度慢
App Router 心智负担高
部署到 Cloudflare 不够原生
Server Actions 更偏 Web 内部,不适合多端 API所以我们重新审视了这几个技术:
TanStack Start
TanStack Server Functions
TanStack Server Routes
Hono
Hono RPC
oRPC最终结论是:
只有 Web 时,TanStack Start 自己就够了。 需要独立 API 层时,再引入 Hono。 确定要做多端、公共 API、AI Agent 或长期 API 合约时,再引入 oRPC。
也就是说,默认方案不应该直接写成:
TanStack Start + Hono + oRPC更合理的做法是分阶段、按需求引入。
阅读前先准备
| 准备项 | 用途 |
|---|---|
| 一个真实项目边界 | 先知道你只做 Web,还是未来要多端、Agent 或公共 API |
| 一个部署目标 | Cloudflare、Zeabur、Node/Docker 会影响框架选择 |
| 基础 API 概念 | 理解 Server Functions、Server Routes、Hono、oRPC 分别解决什么 |
| AI coding agent | 用来检查现有仓库、迁移路由、跑构建和验证改动 |
| 当前项目的检查命令 | 选型不是口头判断,最终要通过 dev、build、type-check 或测试验证 |
这篇适合在做技术选型前读。已经开始改仓库时,先确认业务边界,再决定要不要引入 Hono 或 oRPC。
一、我们到底想解决什么问题?
我们不是传统大团队,也不是只做一个固定 SaaS。
我们的真实需求更像:
一个人长期维护
快速做 MVP
部署到 Cloudflare
代码结构简单
AI 容易理解和修改
未来可能支持 Web、小程序、App、Tauri、AI Agent
不想被框架复杂性拖死所以技术选型的核心标准不看"谁最流行",看这些实际因素:
| 标准 | 解释 |
|---|---|
| 开发速度 | 能不能快速把功能做出来 |
| 运行性能 | 访问是否快,部署是否轻 |
| 部署体验 | 能不能舒服地部署到 Cloudflare |
| 心智负担 | 一个人能不能长期维护 |
| AI 友好 | AI 能不能稳定读懂并修改 |
| 多端能力 | 未来是否能支持小程序、App、桌面端、Agent |
| API 长期性 | API 是否能成为长期资产,而不是页面内部函数 |
二、Next.js 的问题:不一定适合这个目标
Next.js 仍然是非常强的框架。
它适合:
内容站
SEO 站
标准 SaaS
Vercel-first 项目
需要大量模板和生态的项目
团队协作和招聘友好的项目但对个人独立开发者来说,它的问题也很明显:
| 问题 | 影响 |
|---|---|
| 框架变重 | 小项目也容易被复杂度拖慢 |
| App Router 心智负担高 | Server Component、Client Component、Server Action、Route Handler、Cache、Runtime 很容易混乱 |
| 热重载慢 | 影响开发节奏 |
| Cloudflare 部署不够原生 | 经常需要适配层 |
| Server Actions 偏 Web 内部 | 多端复用不自然 |
所以我们的判断不是:
Next.js 不行。
而是:
Next.js 不应该再作为所有项目的默认选择。
对于内容站、文档站、SEO 站,Next.js / Fumadocs / Astro 仍然可以继续用。 但对于 Cloudflare-first 的交互型产品、MVP、小工具、多端应用,我们可以考虑新的默认栈。
三、TanStack Start 的定位
TanStack Start 是一个基于 TanStack Router 和 Vite 的全栈 React 框架,官方定位包括 SSR、Streaming、Server Functions、Bundling 等能力。它基于 Vite,因此整体开发体验更轻,更适合 Cloudflare-first 和现代 Web Runtime 的思路。(TanStack)
我们可以把它理解成:
一个更轻、更 Vite、更类型安全路由友好的 React 全栈框架。
它没有替代 Next.js 的所有场景,更适合:
交互型 Web App
Dashboard
AI 工具站
个人产品
Cloudflare-first 应用
快速 MVP四、TanStack Start 里其实已经有两种后端能力
这是本次讨论里最关键的修正。
一开始容易误以为:
Webhook、上传、AI Streaming、第三方回调都要 Hono但其实不准确。
TanStack Start 自己已经有:
Server Functions
Server Routes这两者要分清。
五、Server Functions vs Server Routes vs Hono vs oRPC
1. 总览表
| 类型 | Server Functions | Server Routes | Hono | oRPC |
|---|---|---|---|---|
| 一句话理解 | 页面里直接调用的服务端函数 | TanStack Start 里的 HTTP endpoint | 轻量后端 API 框架 | 类型安全 API 合约层 |
| 主要解决 | 页面内部服务端逻辑 | Webhook、上传、回调、原始 HTTP | 独立 API 服务 | 多端复用、API 合约、OpenAPI |
| 是否必须 | Web 项目常用 | 有 HTTP endpoint 时用 | 不一定 | 不一定 |
| 是否适合公共 API | 不适合 | 可以 | 适合 | 适合 |
| 是否适合多端 | 弱 | 中 | 强 | 很强 |
| 是否适合小项目 | 很适合 | 很适合 | 看情况 | 可能偏重 |
| 最适合 | 页面 CRUD、表单、Dashboard | Webhook、Upload、SSE、Callback | API 服务、Webhook、公共接口 | Web/App/小程序/Agent 共用 API |
2. 架构决策视角:看痛点和收益
| 类型 | TanStack Server Function | Hono API | oRPC |
|---|---|---|---|
| 一句话理解 | 页面里直接写后端函数 | 轻量高性能 API 框架 | 类型安全 API 合约层 |
| 解决的核心痛点 | 最快把功能做出来 | 后端接口清晰、性能好、Cloudflare 适配好 | 多端调用不失控,API 能长期复用 |
| 最大优势 | 开发快,少写接口样板代码 | 轻、快、标准 HTTP、适合 Webhook/API | 类型安全、接口规范、适合多端和 OpenAPI |
| 对新手友好度 | 高,像写本地函数 | 中,需要理解 API 路由 | 中,需要理解 procedure / contract |
| 对老板的价值 | 快速上线 MVP | 系统边界清晰,未来好扩展 | API 成为资产,方便小程序/App/Agent 复用 |
| 对 Cloudflare 友好度 | 好,跟 TanStack Start 走 | 非常好 | 好,通常挂在 Hono 上 |
| 适合多端吗 | 一般,更偏 Web 内部 | 可以,但需要自己维护类型和文档 | 非常适合 |
| 适合长期产品吗 | 适合页面私有逻辑 | 适合后端服务 | 适合核心业务 API |
| 主要风险 | 逻辑和页面耦合 | 类型、文档、错误格式容易散 | 多一层抽象,小项目可能重 |
| 最适合场景 | MVP、表单提交、页面私有数据 | Webhook、支付、AI 接口、REST API | 小程序、App、Tauri、AI Agent、开放 API |
| 我的建议 | 默认用于页面内部逻辑 | 默认作为后端入口 | 用于长期、多端、核心业务 API |
一句话:
Server Function 负责快,Hono 负责稳,oRPC 负责长期可复用。
3. 工程师视角:看技术边界
| 类型 | TanStack Server Function | Hono API | oRPC |
|---|---|---|---|
| 技术定位 | Full-stack 框架里的 server-only 函数 | HTTP server / router | RPC + API contract |
| 入口形态 | createServerFn() | app.post('/api/posts') | router.posts.create |
| 前端调用方式 | 直接调用函数 | fetch() 或封装 client | client.posts.create() |
| 输入校验 | 可以用 Zod/Valibot | 通常配合 Zod Validator | 通常内置在 procedure/contract 中 |
| 输出类型 | TypeScript 可推断 | 默认不自动推断,除非用 Hono RPC 或手写类型 | 自动推断 |
| 错误处理 | 项目内自定义 | 自己统一 | 更容易统一成 API 层规范 |
| OpenAPI | 不是重点 | 可通过生态实现 | 核心优势之一 |
| 业务语义 | 更像页面动作 | 更像 HTTP endpoint | 更像业务动作 |
| 多端复用 | 弱一些 | 中等 | 强 |
| Webhook 适配 | 一般 | 强 | 可以,但通常仍由 Hono 承载入口 |
| 文件上传/流式响应 | 可以,但不是最自然 | 自然 | 可做业务层,不一定管底层细节 |
| 与 Cloudflare Workers | 好 | 非常好 | 通过 Hono/HTTP adapter 承载 |
| 项目复杂度 | 低 | 中低 | 中高 |
| 最佳使用边界 | 页面私有逻辑 | HTTP/API 边界 | 核心业务 API 合约 |
4. Server Functions
TanStack Start 的 Server Functions 是 same-origin RPC endpoint,更适合应用内部调用。官方文档也提醒:如果是 public APIs 或跨域 endpoint,应使用 Server Routes。(TanStack)
适合:
页面内部表单提交
Dashboard CRUD
读取当前用户数据
保存设置
Web App 内部操作不适合:
公共 API
跨域 API
小程序/App/第三方直接调用简单理解:
Server Functions 是 Web 页面内部最好用的服务端函数。
5. Server Routes
TanStack Start 的 Server Routes 用来创建 server-side endpoints,适合 raw HTTP requests、form submissions、authentication 等场景。(TanStack)
适合:
Stripe webhook
微信支付回调
文件上传
AI Streaming / SSE
第三方 OAuth callback
健康检查
固定 URL endpoint所以如果项目只有 Web,那么:
TanStack Start + Server Functions + Server Routes就已经足够覆盖大多数场景。
只有 Web 时,不一定需要 Hono。
6. Hono
Hono 是一个轻量、高性能、基于 Web Standards 的 Web 框架,很适合 Cloudflare Workers、Deno、Bun、Node 等运行时。(hono.dev)
适合:
独立 API 服务
REST API
Webhook 服务
公共接口
多端共用后端
Cloudflare Worker API
中间件体系更准确地说:
Hono 是当你想把 API 层独立出来时的选择。
如果只是 Web 应用内部逻辑,TanStack Start 自己就够。 如果你想让 API 层和 Web 页面解耦,或者未来要给小程序/App/Agent 共用,Hono 就开始有价值。
7. oRPC
oRPC 的定位是 API 合约层,不负责替代 Hono。
它可以通过 HTTP 暴露 RPC endpoint,也有 Hono Adapter,可以挂在 Hono 上使用。(orpc.dev)
它的价值在于:
输入输出类型安全
业务化 API 调用
更适合多端
更适合公共 API
更适合 OpenAPI / API 文档比如:
await client.posts.update({
id,
title,
content,
})比起普通 REST:
await fetch('/api/posts/post_123', {
method: 'PUT',
body: JSON.stringify({ title, content }),
})oRPC 更像是在调用一个业务能力。
但 oRPC 也不是必须的。如果只是 Web 前端调用自己的后端,Hono RPC 或 Server Functions 往往就够。 如果未来要做小程序、App、Tauri、AI Agent、公共 API,oRPC 才更值得。
六、Hono RPC vs oRPC
Hono 自己也有 RPC 能力。Hono RPC 通过导出服务端 AppType,让客户端基于 Hono 路由推断输入输出类型。(hono.dev)
所以问题是:
既然 Hono RPC 已经有类型安全了,为什么还要 oRPC?
答案是:看你要的是轻量内部调用,还是长期 API 合约。
1. 架构决策视角
| 类型 | Hono RPC | oRPC |
|---|---|---|
| 一句话理解 | Hono 自带的类型安全调用方式 | 更正式的类型安全 API 合约系统 |
| 核心价值 | 轻量、简单、少依赖 | 长期、多端、文档化、API 资产化 |
| 适合谁 | 个人项目、小团队、Web 前后端都用 TS | 长期产品、多端应用、ToB、Agent、小程序 |
| 最大优势 | 学习成本低,直接复用 Hono 路由类型 | API 语义更清楚,更适合跨端和开放接口 |
| 最大痛点 | 更偏 TypeScript 内部项目 | 多一层抽象,早期 MVP 会重一点 |
| 是否适合多端 | 一般,主要适合 TS 客户端 | 非常适合 |
| 是否适合 OpenAPI | 不是核心定位 | 核心价值之一 |
| 是否适合快速 MVP | 适合 | 可以,但不是必要 |
| 是否适合长期模板 | 可以 | 更适合 |
| 我的建议 | 小项目先用 Hono RPC | 长期模板/多端项目上 oRPC |
一句话:
Hono RPC 是"轻量内用";oRPC 是"正式 API 合约"。
2. 工程师视角
| 类型 | Hono RPC | oRPC |
|---|---|---|
| 类型来源 | 从 Hono AppType 推导 | 从 router / procedure / contract 推导 |
| API 组织方式 | HTTP 路由优先 | 业务 procedure 优先 |
| 调用风格 | client.api.posts.$post() | client.posts.create() |
| 路由语义 | 偏 HTTP path/method | 偏业务动作 |
| 前后端耦合 | 前端需要引用 Hono app 类型 | 前端引用 oRPC router/client 类型 |
| TypeScript 项目适配 | 很好 | 很好 |
| 非 TS 客户端 | 一般 | 更好 |
| OpenAPI / API 文档 | 可额外做,但不是核心 | 天然更适合 |
| 中大型项目结构 | 可能受 Hono 路由结构影响 | 更容易按业务模块组织 |
| Monorepo 配置 | 需要处理 AppType 引用 | 也需要处理类型导出,但边界更合约化 |
| 学习成本 | 低 | 中 |
| 最适合 | 内部 Web API | 多端复用 API / 对外 API |
一句话总结:
小项目 / 内部调用:Hono RPC 更轻
长期多端 / API 合约:oRPC 更合适七、一个关键原则:不要重复写两套 API
这是本次讨论最重要的设计原则之一。
不要这样:
PUT /api/posts/:id
POST /rpc/posts.update也就是说,不要同一个业务既写 Hono REST,又写 oRPC。
如果已经有:
app.put('/api/posts/:id', async (c) => {
return c.json(await updatePost(input))
})就不要再写一个:
posts: {
update: os
.input(UpdatePostInput)
.output(PostOutput)
.handler(({ input }) => updatePost(input))
}除非你有明确的兼容需求。
正确做法是二选一:
| 选择 | API 入口 |
|---|---|
| Hono REST / Hono RPC | PUT /api/posts/:id |
| oRPC | client.posts.update() / /rpc/* |
| TanStack Server Function | 只给当前 Web 应用内部调用 |
八、oRPC 和 Hono 的正确关系
oRPC 不应该和 Hono REST 重复写同一个接口。
更合理的架构是:
Hono = HTTP 容器 / Middleware / 特殊 endpoint
oRPC = 多端核心业务 API比如:
Hono:
GET /health
POST /webhooks/stripe
POST /webhooks/wechat-pay
POST /upload
GET /ai/stream
/rpc/* -> oRPC
oRPC:
posts.create
posts.update
users.me
orders.create
events.join也就是说:
| 类型 | 放哪里 |
|---|---|
| 核心业务 API | oRPC |
| Webhook | Hono / Server Routes |
| 文件上传 | Hono / Server Routes |
| AI Streaming / SSE | Hono / Server Routes |
| 健康检查 | Hono / Server Routes |
| 第三方要求固定路径的 endpoint | Hono / Server Routes |
如果只有 Web,不需要 Hono,Server Routes 就能承担这些 HTTP endpoint。 如果有独立 API 层或多端需求,Hono 才更自然。
九、小程序能不能用 oRPC?
后端可以用 oRPC。
但小程序端是否能直接跑 oRPC client,要看它底层是否依赖浏览器标准 fetch,以及是否能适配微信小程序的 wx.request。
更稳的路线是:
后端用 oRPC 定义 API 合约
导出 OpenAPI / HTTP endpoint
小程序端用 wx.request 调用
必要时根据 OpenAPI 生成类型也就是说:
| 方案 | 评价 |
|---|---|
| 小程序直接跑 oRPC client | 可以尝试,但需要验证兼容性 |
| 小程序用 wx.request 调 oRPC HTTP/OpenAPI endpoint | 更稳 |
| 用 OpenAPI 生成小程序 client | 长期更稳 |
所以如果确定做小程序,多端 API 合约是有价值的。 但前端接入方式不一定非要直接使用 oRPC client。
十、代码组织原则与示例
1. 不要把业务逻辑写两遍
oRPC 里写
posts.update,service 里又写updatePost,是不是重复?
答案是:如果业务逻辑写两遍,那就是错的。
推荐结构是:
schema = 输入输出结构
service = 真正业务逻辑
rpc = 把业务逻辑暴露为 API例如:
// schemas/post.ts
export const UpdatePostInputSchema = z.object({
id: z.string(),
title: z.string().min(1),
content: z.string().min(1),
})
export type UpdatePostInput = z.infer<typeof UpdatePostInputSchema>// services/posts.ts
export async function updatePost(input: UpdatePostInput) {
return db.posts.update({
where: { id: input.id },
data: {
title: input.title,
content: input.content,
},
})
}// rpc/posts.ts
export const postsRouter = {
update: os
.input(UpdatePostInputSchema)
.handler(({ input }) => updatePost(input)),
}oRPC 这一层只是:
把内部业务函数变成远程可调用 API。
不是重新写一遍业务逻辑。
如果你觉得每个 API 都写 os.input(...).output(...).handler(...) 太啰嗦,可以后期封装:
update: mutation(UpdatePostInputSchema, PostSchema, updatePost)但不要一开始过度封装。等写了 5–10 个 API 后,模式稳定了再抽 helper。
2. 相同功能的三种写法对比:创建一篇 Post
下面都实现同一个功能:createPost({ title, content }),返回 { id, title, content, createdAt }。
方案 A:TanStack Server Function
// server:定义 server function
import { createServerFn } from '@tanstack/react-start'
import { z } from 'zod'
const CreatePostSchema = z.object({
title: z.string().min(1),
content: z.string().min(1),
})
export const createPost = createServerFn({ method: 'POST' })
.validator((data) => CreatePostSchema.parse(data))
.handler(async ({ data }) => {
const post = await insertPost(data)
return post
})// client:页面中直接调用
const post = await createPost({ data: { title, content } })优点:最少代码、最快开发、类型体验好。 缺点:不是正式 API 合约,多端复用不自然。
方案 B:Hono API
// server:定义 Hono API
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
const app = new Hono()
app.post('/api/posts', zValidator('json', CreatePostSchema), async (c) => {
const input = c.req.valid('json')
const post = await insertPost(input)
return c.json(post)
})// client:前端 fetch 调用
const res = await fetch('/api/posts', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ title, content }),
})
const post = await res.json()优点:边界清楚、标准 HTTP、Cloudflare 友好、任何客户端都能调用。 缺点:前端类型需要自己维护,错误格式容易不统一。
方案 C:Hono + oRPC
// shared schema
const CreatePostSchema = z.object({
title: z.string().min(1),
content: z.string().min(1),
})
const PostSchema = z.object({
id: z.string(),
title: z.string(),
content: z.string(),
createdAt: z.string(),
})// server:定义 oRPC router 并挂到 Hono
import { os } from '@orpc/server'
export const postsRouter = {
create: os
.input(CreatePostSchema)
.output(PostSchema)
.handler(async ({ input }) => insertPost(input)),
}
export const appRouter = { posts: postsRouter }// server:挂到 Hono
import { RPCHandler } from '@orpc/server/fetch'
const handler = new RPCHandler(appRouter)
app.use('/rpc/*', async (c, next) => {
const { matched, response } = await handler.handle(c.req.raw, {
prefix: '/rpc',
context: {},
})
if (matched) return response
await next()
})// client:创建 oRPC client
import { createORPCClient } from '@orpc/client'
import { RPCLink } from '@orpc/client/fetch'
const link = new RPCLink({ url: '/rpc' })
export const client: RouterClient<AppRouter> = createORPCClient(link)// client:页面调用
const post = await client.posts.create({ title, content })优点:前端调用像本地函数、输入输出类型自动对齐、API 语义清晰、未来更适合多端。 缺点:多一层抽象,早期小项目可能显得复杂。
3. 三种代码写法对比总结
| 类型 | TanStack Server Function | Hono API | Hono + oRPC |
|---|---|---|---|
| 前端调用体验 | createPost({ data }) | fetch('/api/posts') | client.posts.create() |
| 后端组织方式 | 函数 | HTTP 路由 | 业务 procedure |
| 样板代码 | 少 | 中 | 中 |
| 类型安全 | 强 | 弱到中 | 强 |
| 多端复用 | 一般 | 中 | 强 |
| API 文档 | 弱 | 中 | 强 |
| 适合新手 | 最简单 | 中 | 中 |
| 适合长期架构 | 中 | 强 | 最强 |
| 最适合 | 快速页面逻辑 | HTTP/API/Webhook | 多端核心业务 API |
十一、最终决策表
1. 按项目类型选择
| 项目类型 | 推荐技术栈 |
|---|---|
| 只有 Web,普通 CRUD | TanStack Start + Server Functions |
| Web + 少量 Webhook / Upload / Callback | TanStack Start + Server Functions + Server Routes |
| Web + 独立 API 层 | TanStack Start + Hono |
| Web + 小程序 / App / Tauri / Agent | TanStack Start + Hono + oRPC |
| 公共 API / ToB API | Hono + oRPC |
| 内容站 / 文档站 / SEO | Next.js / Fumadocs / Astro |
| 标准 Vercel-first SaaS | Next.js |
| Cloudflare-first 个人长期模板 | TanStack Start 起步,按需加入 Hono / oRPC |
2. 按功能选择
| 功能 | 推荐 |
|---|---|
| 页面内部操作 | Server Functions |
| 页面内部表单 | Server Functions |
| Webhook | Server Routes / Hono |
| 文件上传 | Server Routes / Hono |
| AI Streaming / SSE | Server Routes / Hono |
| 第三方回调 | Server Routes / Hono |
| 独立 REST API | Hono |
| 内部类型安全 API | Hono RPC |
| 多端核心业务 API | oRPC |
| 公共 API 文档 | oRPC / Hono OpenAPI |
| 小程序调用 | oRPC/OpenAPI + wx.request 更稳 |
3. 按阶段选择
| 阶段 | 技术选择 |
|---|---|
| 第一阶段:快速 MVP | TanStack Start |
| 第二阶段:Web 稳定产品 | TanStack Start + Server Routes |
| 第三阶段:API 变多 | 引入 Hono |
| 第四阶段:多端复用 | 引入 oRPC |
| 第五阶段:公共 API / Agent / ToB | oRPC + OpenAPI / 文档化 |
十二、推荐架构与模板
1. 推荐分层
products/01mvp/apps/web
TanStack Start
TanStack Router
React
Tailwind / shadcn
server
Hono
middleware
auth
webhook
api boundary
rpc
oRPC router
schemas
procedures
client
db
Drizzle
D1 / Postgres2. 请求流
Web 页面
↓
TanStack Start
↓
页面私有逻辑:Server Function
↓
多端业务逻辑:oRPC Client
↓
Hono /rpc/*
↓
oRPC Router
↓
Drizzle / D1 / Postgres3. 模板 A:Web MVP
TanStack Start
Server Functions
Server Routes
Drizzle
D1 / Postgres
Better Auth
Tailwind / shadcn
Cloudflare适合:个人产品、Dashboard、AI 工具站、活动报名、社区后台、内部工具、快速 MVP。
特点:简单、开发快、维护成本低、不引入多余 API 层。
4. 模板 B:多端长期模板
products/01mvp/apps/web TanStack Start
apps/server Hono
products/01mvp/packages/api oRPC
products/01mvp/packages/db Drizzle
products/01mvp/packages/auth Better Auth
packages/schema Zod / Valibot适合:Web + 小程序、Web + App、Web + Tauri、AI Agent API、公共 API、ToB 项目、长期业务系统。
特点:API 可复用、边界清晰、适合多端、适合文档化、适合长期维护。
十三、现成模板:tsu!stack
如果你不想从零搭建上述架构,社区已经有一个非常完整的开源模板:tsu!stack。
这是一个 Vite Plus (Vite+) TanStack Start monorepo,已经集成了本文讨论的所有核心技术,并且做了 Docker 化和 opinionated 配置。
技术栈全景
| 技术 | 用途 | 替代 |
|---|---|---|
| pnpm | 快速、磁盘高效的包管理器,monorepo 依赖去重 | npm, yarn |
| Vite Plus (Vite+) | 统一工具链:开发、测试、构建 monorepo | Turborepo, Nx, Vitest, Prettier, ESLint, husky, lint-staged |
| TanStack Start | 现代全栈 React 框架,SPA/SSR/ISR,Vite Nitro adapter | Next.js, Remix, React Router |
| Paraglide.js | 编译时 i18n 国际化 | i18next, next-intl |
| Hono | 轻量 Web 服务器,WinterCG 标准,跨平台可移植 | Express.js, Fastify, Elysia.js |
| oRPC | RPC 框架,自动生成 OpenAPI 文档 | tRPC |
| Drizzle ORM | 类型安全轻量 ORM | Prisma, TypeORM |
| PostgreSQL | 开源关系型数据库 | MySQL, MariaDB |
| Better Auth | 自托管认证框架,支持所有主流 OAuth | Auth.js |
| Docker | 容器化开发和部署 | Podman |
| shadcn/ui | 可定制 React 组件库 | Chakra UI, Material UI, Mantine UI |
此外,tsu!stack 还采用了 Feature-Sliced Design (FSD) 架构方法论来组织前端代码,这对中大型项目的长期可维护性很有价值。
为什么推荐 tsu!stack
- 省去 monorepo 搭建成本 — pnpm workspace + Vite+ 工具链已经配好
- Hono + oRPC 已经集成 — 不需要自己处理 oRPC 挂载 Hono 的细节
- 认证即开即用 — Better Auth + OAuth provider 配置已就绪
- i18n 开箱即用 — Paraglide.js 编译时国际化,零运行时开销
- Docker 化 — Dockerfile 和 Docker Compose 配置都有,Coolify 一键部署
- 多种部署变体 — 主分支是分离部署,还提供
variant/merged(合并 Web+Server)和variant/merged-cloudflare(Cloudflare Workers)分支
部署选项
| 方式 | 说明 |
|---|---|
| Docker + Coolify | 分离 Dockerfile 或 Docker Compose,适合自托管 VPS |
| Cloudflare Workers | 使用 variant/merged-cloudflare 分支,边缘部署 |
| 其他平台 | TanStack Start 使用 Nitro,支持 Vercel、AWS Lambda、Deno Deploy 等 |
Live Demo
GitHub: tsu-moe/tsu-stack | 43 Stars
十四、最终结论
这次选型的核心不是:
TanStack Start 一定比 Next.js 好
Hono 一定要用
oRPC 一定要上而是:
用最少的技术,解决当前真实问题;在需求出现时,再引入下一层。
最终原则是:
只有 Web:不要急着上 Hono / oRPC
需要 HTTP endpoint:先用 Server Routes
需要独立 API:再用 Hono
需要多端 API 合约:再用 oRPC
同一个业务 API 不要 Hono REST 和 oRPC 写两遍
业务逻辑只写在 service,一切 API 层都只是暴露方式一句话总结:
TanStack Start 让我们更快做 Web,Hono 让我们更稳地跑 API,oRPC 让我们的 API 能服务多端。 这就是 2026 年,我选择 TanStack Start 而不再默认 Next.js 的原因。
这篇文档有问题?