Guide for TanStack Start — a full-stack React framework powered by TanStack Router and Vite with SSR, streaming, server functions, server routes, and middleware. Use when user asks to "create a TanStack Start app", "set up server functions", "configure TanStack Start", "add SSR to React app", "create API routes with Start", "set up middleware in Start", "deploy TanStack Start", "use createServerFn", "add authentication in Start", "stream data from server functions", "prerender pages", "use SPA mode", "migrate from Next.js to TanStack Start", "set up Tailwind with Start", "configure environment variables", "use sessions in Start", "add SEO meta tags", "use createMiddleware", "configure createStart", "set up src/start.ts", or asks about @tanstack/react-start, createStart, server function validation, file-based routing, selective SSR, Start deployment, ISR, CDN assets, observability, or LLMO optimization. Do NOT use for TanStack Router-only questions (without SSR/Start context), Next.js-only questions, Remix questions, or React Router v7 questions.
Guides developers through TanStack Start setup, server functions, middleware, SSR, and deployment for full-stack React apps.
npx claudepluginhub vcode-sh/vibe-toolsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/api-middleware.mdreferences/api-routing.mdreferences/api-server-functions.mdreferences/auth-sessions.mdreferences/configuration.mdreferences/data-streaming.mdreferences/deployment.mdreferences/migration.mdreferences/observability.mdreferences/patterns.mdreferences/prerendering-caching.mdreferences/seo-llmo.mdreferences/server-entry.mdreferences/server-routes.mdreferences/troubleshooting.mdTanStack Start is a full-stack React framework powered by TanStack Router and Vite. It provides SSR, streaming, server functions, server routes, middleware, and universal deployment. If you only need client-side routing without SSR, streaming, server functions, or middleware, use TanStack Router directly instead of Start. Not for Next.js, Remix, or React Router.
Key differentiators: End-to-end type safety, composable middleware (client + server), selective SSR per route, deployment-agnostic (any Vite-compatible host), explicit over implicit patterns.
RSC support: Available via Composite Components — server-produced React components that the client fetches, caches, and streams. See references/migration.md for details.
pnpm create @tanstack/start@latest
# or
npm create @tanstack/start@latest
Or clone an official example:
npx gitpick TanStack/router/tree/main/examples/react/EXAMPLE_SLUG my-project
Official examples: start-basic, start-basic-auth, start-counter, start-basic-react-query, start-clerk-basic, start-convex-trellaux, start-supabase-basic, start-trellaux, start-workos, start-material-ui.
Install dependencies:
npm i @tanstack/react-start @tanstack/react-router react react-dom
npm i -D vite @vitejs/plugin-react typescript vite-tsconfig-paths @types/node @types/react @types/react-dom
vite.config.ts — Vite plugin configuration:
import { defineConfig } from 'vite'
import tsConfigPaths from 'vite-tsconfig-paths'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
tsConfigPaths(),
tanstackStart(),
viteReact(), // MUST come after tanstackStart()
],
})
Alternative React plugins:
@vitejs/plugin-react-swcor@vitejs/plugin-react-oxccan replace@vitejs/plugin-react.
src/router.tsx — Router configuration:
import { createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
export function getRouter() {
return createRouter({ routeTree, scrollRestoration: true })
}
src/routes/__root.tsx — Root route (HTML shell):
/// <reference types="vite/client" />
import type { ReactNode } from 'react'
import { Outlet, createRootRoute, HeadContent, Scripts } from '@tanstack/react-router'
export const Route = createRootRoute({
head: () => ({
meta: [
{ charSet: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ title: 'My App' },
],
}),
component: () => (
<html><head><HeadContent /></head>
<body><Outlet /><Scripts /></body>
</html>
),
})
package.json scripts:
{ "type": "module", "scripts": { "dev": "vite dev", "build": "vite build" } }
Routes live in src/routes/. The routeTree.gen.ts is auto-generated on dev/build.
| Path | Filename | Type |
|---|---|---|
/ | index.tsx | Index |
/about | about.tsx | Static |
/posts/:id | posts/$postId.tsx | Dynamic |
/rest/* | rest/$.tsx | Wildcard |
| Layout wrapper | _layout.tsx | Pathless layout |
| Grouped dir | (group)/route.tsx | Organization only |
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => fetchPost(params.postId),
component: PostComponent,
})
function PostComponent() {
const post = Route.useLoaderData()
return <h1>{post.title}</h1>
}
Server-only logic callable from anywhere. Created with createServerFn():
import { createServerFn } from '@tanstack/react-start'
export const getUser = createServerFn({ method: 'GET' })
.inputValidator((data: { id: string }) => data)
.handler(async ({ data }) => {
return await db.users.find(data.id) // Runs only on server
})
// Call from loader, component, or other server function
const user = await getUser({ data: { id: '123' } })
Validation with Zod:
import { z } from 'zod'
export const createPost = createServerFn({ method: 'POST' })
.inputValidator(z.object({ title: z.string().min(1), body: z.string() }))
.handler(async ({ data }) => db.posts.create(data))
Redirects & errors:
import { redirect, notFound } from '@tanstack/react-router'
export const requireAuth = createServerFn().handler(async () => {
const user = await getSession()
if (!user) throw redirect({ to: '/login' })
return user
})
Progressive enhancement (no JS):
// Server functions have a .url property for HTML forms
<form method="POST" action={createPost.url}>
<input name="title" />
<button type="submit">Create</button>
</form>
Two types: request middleware (all requests) and server function middleware (server functions only).
import { createMiddleware } from '@tanstack/react-start'
// Request middleware (server only)
const logger = createMiddleware().server(async ({ next, request }) => {
console.log(request.url)
return next()
})
// Server function middleware (client + server)
const auth = createMiddleware({ type: 'function' })
.client(async ({ next }) => next({ headers: { Authorization: `Bearer ${getToken()}` } }))
.server(async ({ next }) => next({ context: { user: await getUser() } }))
Global middleware via src/start.ts:
import { createStart } from '@tanstack/react-start'
export const startInstance = createStart(() => ({
requestMiddleware: [loggerMiddleware],
functionMiddleware: [authMiddleware],
}))
export const Route = createFileRoute('/api/hello')({
server: {
handlers: {
GET: async ({ request }) => Response.json({ message: 'Hello!' }),
POST: async ({ request }) => {
const body = await request.json()
return Response.json({ received: body })
},
},
},
})
import { useSession } from '@tanstack/react-start/server'
function useAppSession() {
return useSession<{ userId?: string }>({
password: process.env.SESSION_SECRET!,
cookie: { secure: process.env.NODE_ENV === 'production', httpOnly: true, sameSite: 'lax' },
})
}
Loaders are ISOMORPHIC — they run on server during SSR AND on client during navigation. Never access process.env secrets directly in loaders. Use createServerFn() instead.
Environment variables — Server: process.env.ANY_VAR. Client: only import.meta.env.VITE_* prefixed. Never prefix secrets with VITE_.
Plugin order — tanstackStart() MUST come before viteReact() in vite.config.ts.
TypeScript — Do NOT enable verbatimModuleSyntax (causes server bundle leaking into client). Required settings: jsx: "react-jsx", moduleResolution: "Bundler", module: "ESNext".
Server function imports — Safe to statically import anywhere. Avoid dynamic imports for server functions.
Execution boundaries — Use createServerOnlyFn() for server-only utilities that throw on client. Use createClientOnlyFn() for browser-only utilities. Use createIsomorphicFn() for environment-specific implementations.
Head management — <HeadContent /> in <head>, <Scripts /> at end of <body>. Both required in root route.
Raw Response — Server functions can return Response objects directly for binary data or custom content types.
Route-level error boundaries with default + per-route override:
// src/router.tsx — default for all routes
export function getRouter() {
return createRouter({
routeTree,
defaultErrorComponent: ({ error, reset }) => <ErrorComponent error={error} />,
})
}
// Per-route override
export const Route = createFileRoute('/posts/$postId')({
errorComponent: ({ error, reset }: ErrorComponentProps) => (
<div><p>Error: {error.message}</p><button onClick={reset}>Retry</button></div>
),
})
Date.now(), Math.random(), locale-dependent APIs in SSR. Fix: use <ClientOnly>, useHydrated(), or suppressHydrationWarning.VITE_ prefix. Restart dev server after adding new vars.process.env in loader (isomorphic!). Move to createServerFn().references/api-routing.md — Routing, createFileRoute, createRootRoute, route hooks, components, error boundaries, navigationreferences/api-server-functions.md — createServerFn, validation, streaming, server context utilities, useSession, environment functions, useServerFnreferences/api-middleware.md — createMiddleware, createStart, custom fetch, header merging, fetch override, createHandlersreferences/server-entry.md — Custom server/client entry, request context, handler callbacks, Cloudflare Workers extensionsreferences/configuration.md — Vite config options, TypeScript, environment variables, path aliases, Tailwind CSS, server build configreferences/auth-sessions.md — Authentication (DIY + partners), sessions, route protection, RBAC, OAuth, password reset, rate limitingreferences/data-streaming.md — Data loading patterns, streaming (async generators, ReadableStream), cache control, TanStack Query integrationreferences/seo-llmo.md — SEO meta tags, JSON-LD structured data, LLMO/AIO optimization, sitemaps, robots.txt, llms.txtreferences/server-routes.md — API endpoints, dynamic params, wildcard routes, request bodies, per-handler middleware, escaped file namesreferences/patterns.md — Markdown rendering, database integration (Neon/Convex/Prisma), file organization, progressive enhancement, execution model, tutorialsreferences/deployment.md — Cloudflare Workers, Netlify, Railway, Vercel, Node.js/Docker, Bun, Appwrite Sites, Nitroreferences/prerendering-caching.md — Static prerendering (SSG), ISR, selective SSR, SPA mode, CDN asset URLsreferences/observability.md — Sentry, New Relic, OpenTelemetry, health checks, metrics collection, loggingreferences/migration.md — Next.js migration guide, framework comparison (Start vs Next.js vs React Router)references/troubleshooting.md — Hydration errors, env variable issues, loader mistakes, middleware problems, production checklist