这是一份 7 天执行路线图,手把手演示如何用 TanStack Start 从零搭建 SaaS:认证、数据库、支付、邮件与部署端到端接线,外加一个受保护路由和一个持久化的示例数据流程。它不是生产就绪的产品,也不是复制粘贴式的完整教程。每一天都写明"当天完成什么、不覆盖什么",让边界始终清晰。这份计划的价值是基础设施跑通、能承载业务代码,而不是产品本身。
如果你还在框架选型阶段,我们此前的对比文章解释了为什么 TanStack Start 适合 Cloudflare 原生 SaaS。关于时间:7 天是一个开发者在这个范围内务实的节奏,不是保证。快一点或慢一点都正常——计划的真正价值在于顺序与验收标准,而不是日历。
第 1 天 — 项目脚手架
完成:一个本地可运行的 TanStack Start 项目。不覆盖:框架底层原理,这一周里你会自然熟悉。
用官方 CLI 创建项目,它会引导你选择包管理器与可选插件:
npx @tanstack/cli@latest createTanStack Start 目前处于 Release Candidate 阶段——按官方说明,功能已完整、API 已稳定。CLI 生成的项目自带 src/routes/ 文件路由结构,本 TanStack Start 教程后面的步骤都建立在它之上。
启动开发服务器,先确认结构就位再继续。请使用官方 CLI 而不是手写配置——生成的项目已经把 Vite、路由与 server entry 接好,这正是本计划后续步骤所依赖的配置。
验收标准:npm run dev(或对应包管理器命令)能打开页面,修改路由文件能热更新。
第 2 天 — 路由与数据加载
完成:几个带 typed loader 的路由。不覆盖:高级渲染策略——MVP 用服务端渲染已经足够。
TanStack Start 构建在 TanStack Router 之上,路由是文件式的且类型安全:loader、路由参数、搜索参数全部带类型。建一个在 loader 里加载数据而不是在组件里请求的路由,页面就能从路由定义自动推导出数据的类型。
实际收益在重构时体现:重命名一条路由或改一个参数,所有被破坏的引用在编译期就会报错,而不是上线后才发现。对两周大的 MVP 代码库这听起来微不足道;六个月后,这就是"安全重命名"与"页面直接挂掉"的区别。loader 还提供了一个统一的加载与错误状态位置,数据在途时界面保持一致。
验收标准:存在两个路由,其中一个带 typed loader;参数名写错时类型检查失败。
第 3 天 — 数据库:Drizzle + Cloudflare D1 + 迁移
完成:Drizzle 接入 Cloudflare D1、schema 与迁移,外加一个小的持久化示例流程。不覆盖:查询优化与备份策略,都可以往后放。
Drizzle 用 TypeScript 定义 schema 并生成 SQL 迁移,不会额外引入运行时依赖,适合 serverless 环境。D1 是 Cloudflare 的 SQLite 数据库,在 Worker 中通过 DB 绑定访问。本计划先接数据库再接认证,因为 Better Auth 的用户表与会话表也要放在这里。
先把 D1 绑定加进 Cloudflare 配置,然后定义第一批表。保留一张示例表,让 MVP 有一个持久化数据流——比如 notes 表(id、title、body):
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
export const notes = sqliteTable('notes', {
id: integer('id').primaryKey({ autoIncrement: true }),
title: text('title').notNull(),
body: text('body'),
})生成并执行迁移,然后通过一个服务端路由各接一次读写,让数据流端到端可见。因为 D1 兼容 SQLite,本地开发可以使用与生产相同的 schema 与驱动——差异只在于绑定指向哪个数据库。
验收标准:路由能从 D1 读、向 D1 写,数据在开发服务器重启后仍在。
第 4 天 — 认证:Better Auth
完成:邮箱密码注册与登录、会话,以及一个受保护路由。不覆盖:邮箱验证暂不做(依赖邮件服务,放到第 6 天);OAuth 是很好的扩展,但每个提供商都需要 Client ID、Client Secret 与回调 URL,不属于 MVP 核心。
Better Auth 官方支持 TanStack Start,并提供 Drizzle 适配器。先安装,设置 BETTER_AUTH_SECRET(至少 32 个字符)与 BETTER_AUTH_URL,然后创建认证实例并启用邮箱密码——同时加上 tanstackStartCookies 插件,由它负责 TanStack Start 的 cookie 设置(它必须是插件数组的最后一位):
import { betterAuth } from 'better-auth'
import { tanstackStartCookies } from 'better-auth/tanstack-start'
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
import { db } from './db'
export const auth = betterAuth({
database: drizzleAdapter(db, { provider: 'sqlite' }),
emailAndPassword: { enabled: true },
plugins: [tanstackStartCookies()],
})用官方 CLI 生成用户表与会话表:
npx auth@latest generate然后沿用第 3 天的流程,为这些新增的 auth 表在本地再生成并应用一次 Drizzle 迁移,并在部署前把这次迁移应用到生产 D1——磁盘上的 schema 不迁移进库,数据库里就没有这些表。
按官方 TanStack Start 集成指南,把 handler 挂到 catch-all 服务端路由上,并创建客户端:
// src/routes/api/auth/$.ts
import { createFileRoute } from '@tanstack/react-router'
import { auth } from '@/lib/auth'
export const Route = createFileRoute('/api/auth/$')({
server: {
handlers: {
GET: async ({ request }) => auth.handler(request),
POST: async ({ request }) => auth.handler(request),
},
},
})受保护路由用 beforeLoad 里的服务端函数检查会话,而不是客户端检查——这样客户端导航也会被拦截。
验收标准:新账户可以注册并登录,会话写入 D1,受保护路由能拦截未登录访客。
第 5 天 — 支付:完整的 Stripe 订阅闭环
完成:一条支付流程端到端跑通。不覆盖:Customer Portal、一次性购买与按用量计费——列为扩展。
选定订阅路径并闭环:
- 配置 Stripe 测试模式,为你的方案建一个测试价格
- 用户点击订阅时,由服务端路由创建 Checkout Session——价格 ID 从配置读取,绝不由客户端传入
- 用 Stripe CLI 本地转发 webhook——
stripe listen会打印该端点的whsec_签名密钥 - 在 webhook 路由中校验签名,再信任任何事件
checkout.session.completed时记录订单并关联订阅;订阅状态由customer.subscription.*生命周期事件维护,且按事件幂等处理——重复投递的事件不会产生重复记录
签名校验是这一天的安全边界。在 Cloudflare Workers 上,需要用基于 fetch 的 HTTP 客户端与 subtle-crypto provider 创建 Stripe 客户端(Workers 没有 Node 的 crypto 模块),密钥从 Worker handler 收到的绑定里读取:
import Stripe from 'stripe'
import { env } from 'cloudflare:workers'
const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
httpClient: Stripe.createFetchHttpClient(),
})
// 在 webhook handler 内;env 来自 Worker 的绑定:
const event = await stripe.webhooks.constructEventAsync(
await request.text(), // Stripe 发送时的原始请求体
request.headers.get('stripe-signature'),
env.STRIPE_WEBHOOK_SECRET,
undefined,
Stripe.createSubtleCryptoProvider(),
)边缘运行时请使用异步验证版本。两个细节决定它能否在生产环境工作:原始请求体要用 request.text() 在任何解析发生之前读取;密钥必须使用接收事件的那个端点对应的密钥。
验收标准:用测试卡订阅后,在已验签的订阅生命周期 webhook 处理完成后,D1 中出现一条有效的订阅记录,而不是在返回页模拟成功。
第 6 天 — 邮件与部署
完成:Resend 交易邮件——含 Better Auth 邮箱验证与购买确认邮件——以及 Cloudflare Workers 部署。不覆盖:邮件模板体系与多环境配置。
Resend 是面向开发者的邮件 API:验证域名、创建 API key 之后,发送就是一次 API 调用。今天启用 Better Auth 的邮箱验证,让用户收到的验证邮件是真实送达的,而不是桩代码。购买确认邮件由同一个已验签的 checkout.session.completed 事件触发——这个时点支付才被确认,所以它是确认邮件的正确触发源。customer.subscription.* 事件负责同步订阅生命周期状态,不是确认邮件的触发源。邮件发送要幂等:以 checkout 事件为键去重,重复投递的 webhook 不会发出重复邮件。
Cloudflare Workers 是 TanStack Start 的官方托管合作伙伴。安装 @cloudflare/vite-plugin 与 wrangler,把插件加进 vite.config.ts,并创建带兼容性标志的 wrangler.jsonc:
{
"name": "tanstack-start-app",
"compatibility_date": "2026-07-16",
"compatibility_flags": ["nodejs_compat"],
"main": "@tanstack/react-start/server-entry"
}上面的兼容日期只是示例——创建文件时请使用与你的 Cloudflare 账户设置一致的近期日期。
然后登录并部署:
npx wrangler login
npm run deploy数据库绑定与密钥按环境配置。把 Stripe webhook 密钥与 Resend key 放进 Cloudflare secrets,绝不放进客户端代码——第 3 天的 D1 绑定也在这里发挥生产价值。
验收标准:部署后的 Worker 正常服务应用,D1 绑定在生产环境可用,收件箱里收到验证邮件和购买确认邮件。
第 7 天 — 验证与打磨
完成:端到端验证与上线检查清单。不覆盖:i18n、主题与 SEO 深度优化——属于上线前增强项,不是 MVP 核心。
在部署后的 URL 上完整走一遍:注册 → 收到并点击验证邮件 → 登录 → 打开受保护路由 → 用测试卡订阅 → 确认 webhook 把订阅写入 D1 → 收到购买后的邮件。
然后检查运维基础项:密钥在 Cloudflare 而不在仓库里、生产环境的迁移已执行、开发与生产行为一致。只在本机正常的地方都要修掉。
验收标准:用全新账户在生产 URL 上完整跑通全流程。
常见错误
本计划里的调试时间经常集中在五类常见错误上:
- 漏掉生产环境的 D1 迁移。 schema 只在本地存在,部署后的数据库没有表——所有查询都会报 table-not-found。迁移要按环境执行,并用真实查询验证。
- 混淆 server/client 边界。 仅服务端代码——数据库访问、认证 handler、密钥——绝不能被客户端组件引入。TanStack Start 官方文档对边界的说明非常明确。
- OAuth 回调 URL 配置错误。 之后接入社交登录时,回调地址必须与提供商登记的值完全一致,包括端口。不一致会表现为让人困惑的重定向错误。
- 跳过 webhook 签名校验。 任何信任原始 webhook 体的端点都可能被伪造。始终把原始 body 与
Stripe-Signature请求头传给constructEventAsync。 - 把密钥放进客户端可读的地方。 服务商密钥与端点密钥属于 Cloudflare secrets,不该出现在打包后的客户端代码里。
7 天后你得到什么
一个可运行的技术型 MVP:类型化路由、D1 支撑的认证、真实的订阅闭环、交易邮件与 Workers 部署。这正是本"用 TanStack Start 搭建 SaaS"计划的落点——持久化、认证与支付都是真的,接下来几周写的是业务代码,而不是管道。
如果你希望直接从一个已经组装好的地基开始,我们的模板清单整理了主流的 TanStack Start 起步套件与模板。如果你想要一个无需自己组装、基于 TanStack Start 的 SaaS MVP,TANSHIP Template 把这些基础(Better Auth、三套支付适配器、Drizzle on D1、R2 存储、Resend 与积分计量的 AI 工作流)封装在一个开箱即配的代码库里。如实说明:TANSHIP Template 是我们开发并销售的产品,它出现在这里,正是为了本计划结尾所指向的场景。
参考来源
- TanStack Start — 入门——CLI 脚手架与项目创建
- TanStack Start — 托管——Cloudflare Workers 部署步骤与官方合作伙伴身份
- Better Auth — 安装——配置、环境变量、schema 生成与 TanStack Start 支持
- Better Auth — TanStack Start 集成——
tanstackStartCookies、/api/auth/$handler 与路由保护 - Drizzle ORM——TypeScript schema 与迁移
- Cloudflare D1——SQLite 数据库与 Worker 绑定
- Stripe — webhook 签名校验——webhook 验证、原始请求体处理与
whsec_密钥 - Resend — 简介——域名验证与交易邮件


