Full-stack React on TanStack Router with per-route SSR/CSR, file-based routing, server functions, and first-class Cloudflare Workers support.
/plugin marketplace add secondsky/claude-skills/plugin install tanstack-start@claude-skillsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/cloudflare-hosting-and-env.mdreferences/devtools-and-llm-support.mdreferences/execution-and-auth.mdreferences/navigation-and-preloading.mdreferences/quickstart-and-layout.mdreferences/rendering-modes.mdreferences/routing-and-data-loading.mdreferences/server-functions-and-middleware.mdscripts/bootstrap-cloudflare-start.shFull-stack React on TanStack Router with per-route SSR/CSR, file-based routing, server functions, and first-class Cloudflare Workers support.
scripts/bootstrap-cloudflare-start.sh <app> scaffolds Start + Workers + binding types.npm create @tanstack/start@latest my-app
cd my-app
npm run dev
Manual installs (all bundle targets are supported): add @tanstack/react-router + @tanstack/react-start with your bundler plugin (vite, webpack, or esbuild) per the official install guides.
app/routes/** file-based routes → router tree, automatic code-splitting + data preloading.app/entry.client.tsx hydrates <StartClient />; app/entry.server.tsx wraps createServerEntry.app/config.ts or app/start.ts sets defaultSsr, spaMode, middleware, and context.createFileRoute() infers path params; add validateSearch (zod) to parse and coerce search params.redirect()/notFound() for control flow.action/server functions; keep loaders read-only and invalidate via router.invalidate() after mutation.QueryClient in router context and ensureQueryData inside loaders to dedupe fetches.head per route for <title>/meta; derive from loader data to keep SEO consistent.notFound() or redirect() in loaders/middleware; use error boundaries for UX.Example route (typed search + data-only SSR):
// app/routes/posts.$postId.tsx
import { createFileRoute, redirect } from '@tanstack/react-router'
import { z } from 'zod'
export const Route = createFileRoute('/posts/$postId')({
validateSearch: z.object({ preview: z.boolean().optional() }),
ssr: 'data-only',
loader: async ({ params, search, context }) => {
const post = await context.queryClient.ensureQueryData(['post', params.postId], () =>
fetch(`/api/posts/${params.postId}?preview=${!!search.preview}`).then(r => r.json())
)
if (!post.published && !search.preview) throw redirect({ to: '/drafts' })
return { post }
},
})
<Link preload="intent"> (hover/focus) preloads route data/code; use preload="render" for above-the-fold routes.router.preloadRoute({ to, search }) to warm caches before navigation (e.g., on visibility)./products?slug=abc masked as /p/abc).router.navigate({ to, replace, from }) blockers or useBlocker.scrollRestoration to restore positions on back/forward; customize per route when using long lists.ssr: true | false | 'data-only' on routes; defaultSsr config sets the baseline.lazy/load for manual chunks on code-based routes.preload="intent" links with defaultPreloadStaleTime to avoid over-fetching.pendingComponent for CSR routes to avoid layout shift.<RouterDevtools /> during development to inspect matches, loader states, and preloading.@tanstack/eslint-plugin-router with the recommended config to enforce inference-sensitive property order (e.g., beforeLoad before loader).Route meta for better AI navigation.cloudflare({ viteEnvironment: { name: 'ssr' } }) first in Vite plugins so bindings reach server entry.npm run cf-typegen.pages.ssr: 'data-only' for non-deterministic UI).validateSearch and custom serializer where needed.create-route-property-order rule) and npm run check passes.router.matches state looks correct.cf-typegen) and streaming tested via curl -N.Use when working with Payload CMS projects (payload.config.ts, collections, fields, hooks, access control, Payload API). Use when debugging validation errors, security issues, relationship queries, transactions, or hook behavior.