tanstack-start by jezweb/claude-skills
npx skills add https://github.com/jezweb/claude-skills --skill tanstack-start从零开始构建一个完整的全栈应用。Claude 生成每个文件 —— 无需模板克隆,无需脚手架命令。每个项目都能获得其所需的一切。
| 层级 | 技术 |
|---|---|
| 框架 | TanStack Start v1 (SSR、基于文件的路由、服务器函数) |
| 前端 | React 19、Tailwind v4、shadcn/ui |
| 后端 | 服务器函数 (通过 Cloudflare Workers 上的 Nitro) |
| 数据库 | D1 + Drizzle ORM |
| 认证 | better-auth (Google OAuth + 邮箱/密码) |
| 部署 | Cloudflare Workers |
询问:
| 必需项 | 可选项 |
|---|---|
| 项目名称 (kebab-case) | Google OAuth 凭据 |
| 一行描述 | 自定义域名 |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| Cloudflare 账户 | 是否需要 R2 存储? |
| 认证方式:Google OAuth、邮箱/密码,或两者兼有 | 管理员邮箱 |
从零创建项目目录和所有配置文件。
查看 references/architecture.md 以获取完整的文件树、所有依赖项和配置模板。
首先创建这些文件:
package.json — 所有运行时 + 开发依赖项,版本范围来自 architecture.mdtsconfig.json — 严格模式,@/* 路径别名映射到 src/*vite.config.ts — 按正确顺序排列插件:cloudflare() → tailwindcss() → tanstackStart() → viteReact()wrangler.jsonc — main: "@tanstack/react-start/server-entry",nodejs_compat 标志,D1 绑定占位符.dev.vars — 使用 openssl rand -hex 32 生成 BETTER_AUTH_SECRET,设置 BETTER_AUTH_URL=http://localhost:3000,TRUSTED_ORIGINS=http://localhost:3000.gitignore — node_modules, .wrangler, dist, .output, .dev.vars, .vinxi, .DS_Store然后:
cd PROJECT_NAME
pnpm install
创建 D1 数据库并更新 wrangler.jsonc:
npx wrangler d1 create PROJECT_NAME-db
# 将 database_id 复制到 wrangler.jsonc 的 d1_databases 绑定中
使用符合 D1 规范的模式创建 Drizzle 模式。
src/db/schema.ts — 定义所有表:
users、sessions、accounts、verifications — 这些是 better-auth 必需的items (或项目所需的任何表) 用于 CRUD 演示D1 特定规则:
integer (Unix 纪元),不要使用 Date 对象text (nanoid/cuid2),不要使用 autoincrementsrc/db/index.ts — Drizzle 客户端工厂:
import { drizzle } from "drizzle-orm/d1";
import { env } from "cloudflare:workers";
import * as schema from "./schema";
export function getDb() {
return drizzle(env.DB, { schema });
}
关键:使用 import { env } from "cloudflare:workers" — 不要使用 process.env。这是一个每个请求的绑定,因此在每个服务器函数内部创建 Drizzle 客户端,而不是在模块级别。
drizzle.config.ts:
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./src/db/schema.ts",
out: "./drizzle",
dialect: "sqlite",
});
将迁移脚本添加到 package.json:
{
"db:generate": "drizzle-kit generate",
"db:migrate:local": "wrangler d1 migrations apply PROJECT_NAME-db --local",
"db:migrate:remote": "wrangler d1 migrations apply PROJECT_NAME-db --remote"
}
生成并应用初始迁移:
pnpm db:generate
pnpm db:migrate:local
src/lib/auth.server.ts — 服务器端 better-auth 配置:
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { drizzle } from "drizzle-orm/d1";
import { env } from "cloudflare:workers";
import * as schema from "../db/schema";
export function getAuth() {
const db = drizzle(env.DB, { schema });
return betterAuth({
database: drizzleAdapter(db, { provider: "sqlite" }),
secret: env.BETTER_AUTH_SECRET,
baseURL: env.BETTER_AUTH_URL,
trustedOrigins: env.TRUSTED_ORIGINS?.split(",") ?? [],
emailAndPassword: { enabled: true },
socialProviders: {
// 如果提供了凭据,则添加 Google OAuth
},
});
}
关键:getAuth() 必须每个请求调用一次 (在处理器/加载器内部),不能在模块级别调用。从 cloudflare:workers 导入的 env 仅在请求处理期间可用。
src/lib/auth.client.ts — 客户端认证钩子:
import { createAuthClient } from "better-auth/react";
export const { useSession, signIn, signOut, signUp } = createAuthClient();
src/routes/api/auth/$.ts — better-auth 的 API 通配路由:
import { createAPIFileRoute } from "@tanstack/react-start/api";
import { getAuth } from "../../../lib/auth.server";
export const APIRoute = createAPIFileRoute("/api/auth/$")({
GET: ({ request }) => getAuth().handler(request),
POST: ({ request }) => getAuth().handler(request),
});
关键:认证必须使用 API 路由 (createAPIFileRoute),不能使用服务器函数 (createServerFn)。better-auth 需要直接访问请求/响应。
src/routes/__root.tsx — 包含 HTML 文档的根布局:
@tanstack/react-router 的 <HeadContent /> 和 <Scripts /><html> 元素上添加 suppressHydrationWarning 以实现 SSR 与主题切换的兼容性src/styles/app.css — Tailwind v4 + shadcn/ui:
@import "tailwindcss" (v4 语法):root 和 .dark 中为 shadcn/ui 令牌定义 CSS 变量src/router.tsx — 路由器配置:
import { createRouter as createTanStackRouter } from "@tanstack/react-router";
import { routeTree } from "./routeTree.gen";
export function createRouter() {
return createTanStackRouter({ routeTree });
}
declare module "@tanstack/react-router" {
interface Register {
router: ReturnType<typeof createRouter>;
}
}
src/client.tsx 和 src/ssr.tsx — 入口点 (标准的 TanStack Start 样板代码)。
安装仪表板所需的 shadcn/ui 组件:
pnpm dlx shadcn@latest init --defaults
pnpm dlx shadcn@latest add button card input label sidebar table dropdown-menu form separator sheet
注意:将 shadcn 配置为使用 src/components 作为组件目录。
主题切换:三态 (浅色 → 深色 → 系统 → 浅色)。将偏好存储在 localStorage 中。在 <html> 上应用 .dark 类。使用仅限 JS 的系统偏好检测 — 不要使用 CSS @media (prefers-color-scheme) 查询。
创建路由文件:
src/routes/
├── __root.tsx # 根布局 (HTML 外壳、主题、CSS)
├── index.tsx # 着陆页 → 如果已认证则重定向到 /dashboard
├── login.tsx # 登录表单 (邮箱/密码 + Google OAuth 按钮)
├── register.tsx # 注册表单
├── _authed.tsx # 认证守卫布局 (beforeLoad 检查会话)
└── _authed/
├── dashboard.tsx # 统计卡片概览
├── items.tsx # 项目列表 (带操作的表)
├── items.$id.tsx # 编辑项目表单
└── items.new.tsx # 创建项目表单
认证守卫模式 (_authed.tsx):
import { createFileRoute, redirect } from "@tanstack/react-router";
import { getSessionFn } from "../server/auth";
export const Route = createFileRoute("/_authed")({
beforeLoad: async () => {
const session = await getSessionFn();
if (!session) {
throw redirect({ to: "/login" });
}
return { session };
},
});
组件 (位于 src/components/):
app-sidebar.tsx — 带有导航链接 (仪表板、项目) 的 shadcn Sidebartheme-toggle.tsx — 三态主题切换按钮user-nav.tsx — 包含登出操作的用户下拉菜单stat-card.tsx — 用于仪表板的可重用统计卡片查看 references/server-functions.md 以获取在路由加载器和变更中使用的 createServerFn 模式。
为项目资源创建服务器函数:
| 函数 | 方法 | 用途 |
|---|---|---|
getItems | GET | 列出当前用户的所有项目 |
getItem | GET | 按 ID 获取单个项目 |
createItem | POST | 创建新项目 |
updateItem | POST | 更新现有项目 |
deleteItem | POST | 按 ID 删除项目 |
每个服务器函数:
getDb() 创建每个请求的 Drizzle 客户端路由加载器调用 GET 服务器函数。变更调用 POST 服务器函数,然后调用 router.invalidate() 以重新获取数据。
pnpm dev
验证清单:
# 设置生产环境密钥
openssl rand -hex 32 | npx wrangler secret put BETTER_AUTH_SECRET
echo "https://PROJECT.SUBDOMAIN.workers.dev" | npx wrangler secret put BETTER_AUTH_URL
echo "http://localhost:3000,https://PROJECT.SUBDOMAIN.workers.dev" | npx wrangler secret put TRUSTED_ORIGINS
# 如果使用 Google OAuth
echo "your-client-id" | npx wrangler secret put GOOGLE_CLIENT_ID
echo "your-client-secret" | npx wrangler secret put GOOGLE_CLIENT_SECRET
# 迁移远程数据库
pnpm db:migrate:remote
# 构建并部署
pnpm build && npx wrangler deploy
首次部署后:使用实际的 Worker URL 更新 BETTER_AUTH_URL。将生产 URL 添加到 Google OAuth 重定向 URI:https://your-app.workers.dev/api/auth/callback/google。
查看 references/deployment.md 以获取完整的生产环境检查清单和常见错误。
| 症状 | 修复方法 |
|---|---|
服务器函数中 env 未定义 | 使用 import { env } from "cloudflare:workers" — 必须在请求处理器内部,不能在模块作用域 |
| 找不到 D1 数据库 | 检查 wrangler.jsonc 中 d1_databases 绑定名称是否与代码匹配 |
| 认证重定向循环 | BETTER_AUTH_URL 必须与实际的 URL 完全匹配 (协议 + 域名,无尾部斜杠) |
| 认证静默失败 (重定向到主页) | 使用所有有效 URL (逗号分隔) 设置 TRUSTED_ORIGINS 密钥 |
| 开发环境中样式未加载 | 确保 @tailwindcss/vite 插件在 vite.config.ts 中 |
| SSR 水合不匹配 | 在 <html> 元素上添加 suppressHydrationWarning |
| 在 Cloudflare 上构建失败 | 检查 wrangler.jsonc 中的 nodejs_compat 兼容性标志和 main 字段 |
| 密钥未生效 | wrangler secret put 不会重新部署 — 之后运行 npx wrangler deploy |
每周安装量
973
代码仓库
GitHub 星标数
643
首次出现
2026 年 1 月 31 日
安全审计
安装于
opencode825
codex787
gemini-cli774
github-copilot755
cursor718
amp670
Build a complete full-stack app from nothing. Claude generates every file — no template clone, no scaffold command. Each project gets exactly what it needs.
| Layer | Technology |
|---|---|
| Framework | TanStack Start v1 (SSR, file-based routing, server functions) |
| Frontend | React 19, Tailwind v4, shadcn/ui |
| Backend | Server functions (via Nitro on Cloudflare Workers) |
| Database | D1 + Drizzle ORM |
| Auth | better-auth (Google OAuth + email/password) |
| Deployment | Cloudflare Workers |
Ask for:
| Required | Optional |
|---|---|
| Project name (kebab-case) | Google OAuth credentials |
| One-line description | Custom domain |
| Cloudflare account | R2 storage needed? |
| Auth method: Google OAuth, email/password, or both | Admin email |
Create the project directory and all config files from scratch.
Seereferences/architecture.md for the complete file tree, all dependencies, and config templates.
Create these files first:
package.json — all runtime + dev dependencies with version ranges from architecture.mdtsconfig.json — strict mode, @/* path alias mapped to src/*vite.config.ts — plugins in correct order: cloudflare() → tailwindcss() → tanstackStart() → viteReact()wrangler.jsonc — , flag, D1 binding placeholderThen:
cd PROJECT_NAME
pnpm install
Create D1 database and update wrangler.jsonc:
npx wrangler d1 create PROJECT_NAME-db
# Copy the database_id into wrangler.jsonc d1_databases binding
Create the Drizzle schema with D1-correct patterns.
src/db/schema.ts — Define all tables:
users, sessions, accounts, verifications — these are required by better-authitems (or whatever the project needs) for CRUD demoD1-specific rules:
integer for timestamps (Unix epoch), NOT Date objectstext for primary keys (nanoid/cuid2), NOT autoincrementsrc/db/index.ts — Drizzle client factory:
import { drizzle } from "drizzle-orm/d1";
import { env } from "cloudflare:workers";
import * as schema from "./schema";
export function getDb() {
return drizzle(env.DB, { schema });
}
CRITICAL : Use import { env } from "cloudflare:workers" — NOT process.env. This is a per-request binding, so create the Drizzle client inside each server function, not at module level.
drizzle.config.ts :
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./src/db/schema.ts",
out: "./drizzle",
dialect: "sqlite",
});
Add migration scripts to package.json:
{
"db:generate": "drizzle-kit generate",
"db:migrate:local": "wrangler d1 migrations apply PROJECT_NAME-db --local",
"db:migrate:remote": "wrangler d1 migrations apply PROJECT_NAME-db --remote"
}
Generate and apply the initial migration:
pnpm db:generate
pnpm db:migrate:local
src/lib/auth.server.ts — Server-side better-auth configuration:
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { drizzle } from "drizzle-orm/d1";
import { env } from "cloudflare:workers";
import * as schema from "../db/schema";
export function getAuth() {
const db = drizzle(env.DB, { schema });
return betterAuth({
database: drizzleAdapter(db, { provider: "sqlite" }),
secret: env.BETTER_AUTH_SECRET,
baseURL: env.BETTER_AUTH_URL,
trustedOrigins: env.TRUSTED_ORIGINS?.split(",") ?? [],
emailAndPassword: { enabled: true },
socialProviders: {
// Add Google OAuth if credentials provided
},
});
}
CRITICAL : getAuth() must be called per-request (inside handler/loader), NOT at module level. The env import from cloudflare:workers is only available during request handling.
src/lib/auth.client.ts — Client-side auth hooks:
import { createAuthClient } from "better-auth/react";
export const { useSession, signIn, signOut, signUp } = createAuthClient();
src/routes/api/auth/$.ts — API catch-all route for better-auth:
import { createAPIFileRoute } from "@tanstack/react-start/api";
import { getAuth } from "../../../lib/auth.server";
export const APIRoute = createAPIFileRoute("/api/auth/$")({
GET: ({ request }) => getAuth().handler(request),
POST: ({ request }) => getAuth().handler(request),
});
CRITICAL : Auth MUST use an API route (createAPIFileRoute), NOT a server function (createServerFn). better-auth needs direct request/response access.
src/routes/__root.tsx — Root layout with HTML document:
<HeadContent /> and <Scripts /> from @tanstack/react-routersuppressHydrationWarning on <html> for SSR + theme toggle compatibilitysrc/styles/app.css — Tailwind v4 + shadcn/ui:
@import "tailwindcss" (v4 syntax):root and .darksrc/router.tsx — Router configuration:
import { createRouter as createTanStackRouter } from "@tanstack/react-router";
import { routeTree } from "./routeTree.gen";
export function createRouter() {
return createTanStackRouter({ routeTree });
}
declare module "@tanstack/react-router" {
interface Register {
router: ReturnType<typeof createRouter>;
}
}
src/client.tsx and src/ssr.tsx — Entry points (standard TanStack Start boilerplate).
Install shadcn/ui components needed for the dashboard:
pnpm dlx shadcn@latest init --defaults
pnpm dlx shadcn@latest add button card input label sidebar table dropdown-menu form separator sheet
Note : Configure shadcn to use src/components as the components directory.
Theme toggle: three-state (light → dark → system → light). Store preference in localStorage. Apply .dark class on <html>. Use JS-only system preference detection — NO CSS @media (prefers-color-scheme) queries.
Create the route files:
src/routes/
├── __root.tsx # Root layout (HTML shell, theme, CSS)
├── index.tsx # Landing → redirect to /dashboard if authenticated
├── login.tsx # Login form (email/password + Google OAuth button)
├── register.tsx # Registration form
├── _authed.tsx # Auth guard layout (beforeLoad checks session)
└── _authed/
├── dashboard.tsx # Stat cards overview
├── items.tsx # Items list (table with actions)
├── items.$id.tsx # Edit item form
└── items.new.tsx # Create item form
Auth guard pattern (_authed.tsx):
import { createFileRoute, redirect } from "@tanstack/react-router";
import { getSessionFn } from "../server/auth";
export const Route = createFileRoute("/_authed")({
beforeLoad: async () => {
const session = await getSessionFn();
if (!session) {
throw redirect({ to: "/login" });
}
return { session };
},
});
Components (in src/components/):
app-sidebar.tsx — shadcn Sidebar with navigation links (Dashboard, Items)theme-toggle.tsx — three-state theme toggle buttonuser-nav.tsx — user dropdown menu with sign-out actionstat-card.tsx — reusable stat card for the dashboardSeereferences/server-functions.md for createServerFn patterns used in route loaders and mutations.
Create server functions for the items resource:
| Function | Method | Purpose |
|---|---|---|
getItems | GET | List all items for current user |
getItem | GET | Get single item by ID |
createItem | POST | Create new item |
updateItem | POST | Update existing item |
deleteItem | POST | Delete item by ID |
Each server function:
getDb()Route loaders call GET server functions. Mutations call POST server functions then router.invalidate() to refetch.
pnpm dev
Verification checklist:
# Set production secrets
openssl rand -hex 32 | npx wrangler secret put BETTER_AUTH_SECRET
echo "https://PROJECT.SUBDOMAIN.workers.dev" | npx wrangler secret put BETTER_AUTH_URL
echo "http://localhost:3000,https://PROJECT.SUBDOMAIN.workers.dev" | npx wrangler secret put TRUSTED_ORIGINS
# If using Google OAuth
echo "your-client-id" | npx wrangler secret put GOOGLE_CLIENT_ID
echo "your-client-secret" | npx wrangler secret put GOOGLE_CLIENT_SECRET
# Migrate remote database
pnpm db:migrate:remote
# Build and deploy
pnpm build && npx wrangler deploy
After first deploy : Update BETTER_AUTH_URL with your actual Worker URL. Add production URL to Google OAuth redirect URIs: https://your-app.workers.dev/api/auth/callback/google.
Seereferences/deployment.md for the full production checklist and common mistakes.
| Symptom | Fix |
|---|---|
env is undefined in server function | Use import { env } from "cloudflare:workers" — must be inside request handler, not module scope |
| D1 database not found | Check wrangler.jsonc d1_databases binding name matches code |
| Auth redirect loop | BETTER_AUTH_URL must match actual URL exactly (protocol + domain, no trailing slash) |
| Auth silently fails (redirects to home) | Set TRUSTED_ORIGINS secret with all valid URLs (comma-separated) |
| Styles not loading in dev | Ensure @tailwindcss/vite plugin is in vite.config.ts |
Weekly Installs
973
Repository
GitHub Stars
643
First Seen
Jan 31, 2026
Security Audits
Gen Agent Trust HubPassSocketWarnSnykPass
Installed on
opencode825
codex787
gemini-cli774
github-copilot755
cursor718
amp670
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
102,200 周安装
Grimoire CLI 使用指南:区块链法术编写、验证与执行全流程
940 周安装
Grimoire Uniswap 技能:查询 Uniswap 元数据与生成代币/资金池快照的 CLI 工具
940 周安装
Grimoire Aave 技能:查询 Aave V3 元数据和储备快照的 CLI 工具
941 周安装
Railway CLI 部署指南:使用 railway up 命令快速部署代码到 Railway 平台
942 周安装
n8n Python 代码节点使用指南:在自动化工作流中编写 Python 脚本
943 周安装
Flutter Platform Views 实现指南:Android/iOS/macOS原生视图与Web嵌入教程
943 周安装
main: "@tanstack/react-start/server-entry"nodejs_compat.dev.vars — generate BETTER_AUTH_SECRET with openssl rand -hex 32, set BETTER_AUTH_URL=http://localhost:3000, TRUSTED_ORIGINS=http://localhost:3000.gitignore — node_modules, .wrangler, dist, .output, .dev.vars, .vinxi, .DS_Store| SSR hydration mismatch | Add suppressHydrationWarning to <html> element |
| Build fails on Cloudflare | Check nodejs_compat in compatibility_flags, main field in wrangler.jsonc |
| Secrets not taking effect | wrangler secret put does NOT redeploy — run npx wrangler deploy after |