tanstack-start
Skill4 starsChanged 20 days agoMITView on GitHub
TanStack Start, the full-stack React framework built on TanStack Router with Vite or Rsbuild. Use when setting up or reviewing a `@tanstack/react-start` project — the build-tool plugin, SSR and selective SSR, server functions (`createServerFn`), server routes, middleware, prerendering, SPA mode, environment variables, or deployment targets.
- Reads credentials
8 other projects use a version of this.
Adopted by
Most recently taken up by
- vercel-labs/json-rendertheir own version, first seen Oct 29, 2026
- itsLeonB/agent-config-managertheir own version, first seen Oct 20, 2026
- rockcookies/skillstheir own version, first seen Oct 13, 2026
- joelhooks/joelclawtheir own version, first seen Oct 8, 2026
- Mindrally/skillstheir own version, first seen Oct 8, 2026
- authdog/agent-skillstheir own version, first seen Sep 18, 2026
Other versions8 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 8
- vercel-labs/json-render★ 19ksame name
- Mindrally/skills★ 275same name
- dlupiak/claude-session-dashboard★ 66same name
- joelhooks/joelclaw★ 65same name
- Aver005/agent-skills★ 2same name
- rockcookies/skills★ 1same name
- authdog/agent-skills★ 0same name
- itsLeonB/agent-config-manager★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository39 other files it gives its agents.
- AGENTS.mdAGENTS.md
- authoringSkill
- chrome-devtoolsSkill
- gamificationSkill
- imagegenSkill
- improve-architectureSkill
- instructionsSkill
- monorepoSkill
- reverse-engineerSkill
- runbookSkill
- security-reviewSkill
- setup-harnessSkill
- skillsSkill
- unslopSkill
- video-reportSkill
- youtube-transcriptSkill
- code-reviewSkill
- debugSkill
- interviewSkill
- prototypeSkill
- researchSkill
- workSkill
- adsenseSkill
- astryxSkill
- cloudflare-cliSkill
- dokploy-best-practicesSkill
- extract-themeSkill
- nextjsSkill
- payload-cmsSkill
- shadersSkill
- swrSkill
- tanstack-querySkill
- tanstack-routerSkill
- tanstack-storeSkill
- tauriSkill
- vite-plusSkill
- web-assets-optimizationSkill
- web-extensionSkill
- zodSkill
The file
We split this skill into the rules it gives an agent
10 rules. 0 are common, 2 are distinctive, and 8 are very specific to this project.
0
Common
Most of the 5 edited versions we read keep these.
2
Distinctive
This author's own choices. Worth a look.
8
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 24
Start is at Release Candidate stage: the API is considered stable and feature-complete, but not bug-free.
- Very specific: line 47
Read the build config (vite.config.ts / rsbuild.config.ts) before changing anything: prerender, spa, pages, serverFns, and server.build all …
- Very specific: line 50
Look for src/start.ts. If it exists, Start does not auto-install the CSRF middleware — that file owns global request and function …
- Distinctive: line 54
Check whether a host adapter plugin is already wired in (Cloudflare, Netlify, Nitro) — plugin order in the array matters.
- Very specific: line 190
Every route matching the initial request is server-rendered by default.
- Very specific: line 225
Always call next(); the chain stops otherwise.
- Very specific: line 233
Start loads .env, .env.development, .env.production, and .env.local automatically.
- Very specific: line 239
Read process.env inside handlers and middleware, not at module scope.
- Very specific: line 253
Every server function has a .validator() when it takes input, and the validated value is checked for authorization, not just shape — a …
- Very specific: line 259
No secret is read at module scope, and no secret sits behind a VITE_ or PUBLIC_ prefix.
“Common” is measured: kept by at least 6 in 10 of the 5 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
TanStack Start
Reference for TanStack Start, a full-stack React framework powered by TanStack Router. Start adds full-document SSR, streaming, server functions, server routes, middleware, and full-stack builds on top of Router; Router itself still owns routing, loaders, search params, and navigation.
Routing belongs to the sibling skill — see tanstack-router for file-based routes, loaders, search-param validation, and navigation. This skill covers only what Start adds on top. For server-state caching inside components, see tanstack-query.
Start is at Release Candidate stage: the API is considered stable and feature-complete, but not bug-free.
Branch-specific references, loaded on demand:
- server-functions.md —
createServerFn, validators, serialization, errors, redirects, streaming, static server functions. - middleware.md — request vs function middleware, context
passing, global middleware in
src/start.ts, CSRF. - server-routes.md — HTTP endpoints defined with the
serverproperty on file routes. - rendering.md — selective SSR, SPA mode, static prerendering, and ISR-style cache headers.
- deployment.md — hosting targets, environment variables, and build outputs.
First Checks
- Confirm
@tanstack/react-startand@tanstack/react-routerare installed, and which build tool the project uses — Vite (@tanstack/react-start/plugin/vite) or Rsbuild (@tanstack/react-start/plugin/rsbuild). The plugin import path and several config shapes differ between them. - Read the build config (
vite.config.ts/rsbuild.config.ts) before changing anything:prerender,spa,pages,serverFns, andserver.buildall live in thetanstackStart()options. - Look for
src/start.ts. If it exists, Start does not auto-install the CSRF middleware — that file owns global request and function middleware. - Find
src/router.tsx(router creation) andsrc/routes/__root.tsx(the document shell withHeadContentandScripts); both are required. - Check whether a host adapter plugin is already wired in (Cloudflare, Netlify, Nitro) — plugin order in the array matters.
Project Setup
Scaffold with npx @tanstack/cli@latest create, or clone an official example
with npx gitpick TanStack/router/tree/main/examples/react/start-basic.
Minimal dependency set: @tanstack/react-start, @tanstack/react-router,
react, react-dom, plus the build tool (vite + @vitejs/plugin-react, or
@rsbuild/core + @rsbuild/plugin-react).
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'
export default defineConfig({
server: { port: 3000 },
plugins: [
tanstackStart(),
// react's vite plugin must come after start's vite plugin
viteReact(),
],
})Rules that bite:
- The React plugin must come after
tanstackStart()in the Vite plugin array. package.jsonneeds"type": "module".- In
tsconfig.json, keepverbatimModuleSyntaxdisabled — enabling it can leak server bundles into client bundles. Use"jsx": "react-jsx","moduleResolution": "Bundler","module": "ESNext",strictNullChecks. src/routeTree.gen.tsis generated on first run; do not hand-edit it.
Two files are required beyond the config:
// src/router.tsx
import { createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
export function getRouter() {
return createRouter({ routeTree, scrollRestoration: true })
}// src/routes/__root.tsx
import {
createRootRoute,
HeadContent,
Outlet,
Scripts,
} from '@tanstack/react-router'
export const Route = createRootRoute({
head: () => ({
meta: [{ charSet: 'utf-8' }, { title: 'App' }],
}),
component: () => (
<html>
<head>
<HeadContent />
</head>
<body>
<Outlet />
<Scripts />
</body>
</html>
),
})HeadContent and Scripts are not optional: without them, head tags and the
client bundle never reach the document.
Server Functions vs Server Routes
Both run on the server; they answer different questions.
| Need | Use | Why |
| Call server logic from your own app (loaders, components, handlers) | createServerFn | Start handles serialization and typing across the boundary. |
| An HTTP endpoint called from outside the app (webhooks, third parties, OAuth callbacks) | Server route (server.handlers on a file route) | Raw Request/Response, no Start client required. |
Server functions are same-origin RPC endpoints protected by CSRF checks; they are not a public API surface. Server routes are.
import { createServerFn } from '@tanstack/react-start'
import { z } from 'zod'
const CreateUser = z.object({ name: z.string().min(1) })
export const createUser = createServerFn({ method: 'POST' })
.validator(CreateUser)
.handler(async ({ data }) => {
return db.users.create(data)
})Details in server-functions.md and server-routes.md.
Where Code Runs
Route loader and beforeLoad are isomorphic: they run on the server for
the initial request and on the client for subsequent navigations. Reading
process.env.SECRET in a loader exposes it to the client bundle. Put
server-only work behind a server function.
import {
createServerOnlyFn,
createClientOnlyFn,
createIsomorphicFn,
} from '@tanstack/react-start'
const getSecret = createServerOnlyFn(() => process.env.API_SECRET)
const saveLocal = createClientOnlyFn((v: string) => localStorage.setItem('k', v))
const log = createIsomorphicFn()
.server((m: string) => console.log(`[SERVER] ${m}`))
.client((m: string) => console.log(`[CLIENT] ${m}`))Server functions can be statically imported anywhere, including client
components — the build replaces the implementation with an RPC stub. Avoid
await import() of server-function modules; dynamic imports break that
transformation.
Rendering Strategy
Every route matching the initial request is server-rendered by default. Narrow
it per route with ssr:
| Value | beforeLoad / loader on server | Component SSR |
true (default) | yes | yes |
'data-only' | yes | no |
false | no | no |
Change the app-wide default with defaultSsr in createStart. Inheritance is
one-way: a child can only make the inherited value more restrictive, so
ssr: true under a parent with ssr: false has no effect.
For a fully client-rendered app, use SPA mode (spa: { enabled: true }), which
prerenders a shell to /_shell.html. See rendering.md.
Middleware
createMiddleware() produces request middleware, which runs for every server
request including SSR and server functions.
createMiddleware({ type: 'function' }) produces server-function middleware,
which additionally supports .client() and .validator().
import { createMiddleware } from '@tanstack/react-start'
export const authMiddleware = createMiddleware().server(
async ({ next, request }) => {
const session = await auth.getSession({ headers: request.headers })
if (!session) throw new Error('Unauthorized')
return next({ context: { session } })
},
)Always call next(); the chain stops otherwise. Attach auth middleware to
every server function that reads or writes private data — a route beforeLoad
guard is UX, not the data boundary, because server functions are reachable
independently of the UI that calls them. Full model in
middleware.md.
Environment Variables
Start loads .env, .env.development, .env.production, and .env.local
automatically.
- Server code reads any variable from
process.env. - Client code only sees the build tool's public prefix:
VITE_for Vite,PUBLIC_for Rsbuild, viaimport.meta.env. - Read
process.envinside handlers and middleware, not at module scope. On Cloudflare Workers and similar edge runtimes, env is injected per request, so module-scope reads evaluate toundefined. - To get a runtime (not build-time) value to the client, return it from a server function and pass it through a loader.
More, including typing and staticNodeEnv, in deployment.md.
Review Checklist
- Build config is coherent:
tanstackStart()before the React plugin (Vite),"type": "module",verbatimModuleSyntaxdisabled. __root.tsxrendersHeadContentandScripts;routeTree.gen.tsis generated, not hand-edited.- Every server function has a
.validator()when it takes input, and the validated value is checked for authorization, not just shape — a well-formed id is not an authorized id. - Auth middleware is attached to the server functions and server routes that
touch private data, not only to route
beforeLoad. src/start.ts, when present, installscreateCsrfMiddleware()explicitly.- No secret is read at module scope, and no secret sits behind a
VITE_orPUBLIC_prefix. - Loaders contain no server-only assumptions; server work goes through
createServerFnorcreateServerOnlyFn. Cache-Controlon anything identity-dependent isprivateorno-store, neverpublic(rendering.md).- Routes needing browser APIs set
ssr: falseor'data-only'and provide apendingComponentfallback. - SPA-mode and static-host redirects allow
/_serverFn/*and server-route paths through to the server (rendering.md). - Deployment target matches the build output and start script (deployment.md).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

