Files
english/.opencode/skills/tanstack/references/tanstack-start.md
2026-04-12 01:06:31 +07:00

2.9 KiB

TanStack Start Reference

CLI Commands

npm create @tanstack/start@latest         # scaffold project
npm run dev                               # vite dev server
npm run build                             # production build
NITRO_PRESET=cloudflare-workers npm run build  # deploy target

app.config.ts

import { defineConfig } from '@tanstack/react-start/config'
export default defineConfig({
  server: { preset: 'node-server' }, // or 'cloudflare-workers', 'vercel', etc.
  tsr: { autoCodeSplitting: true },
})

File-Based Routing Conventions

Pattern Route
index.tsx /
about.tsx /about
posts.$postId.tsx /posts/:postId
posts_.tsx Layout for /posts/*
_layout.tsx Pathless layout group
__root.tsx Root layout (required)

routeTree.gen.ts is auto-generated — never edit manually.

createFileRoute

export const Route = createFileRoute('/posts/$postId')({
  validateSearch: z.object({ page: z.number().optional() }),
  loader: async ({ params, context }) => fetchPost(params.postId),
  pendingComponent: () => <Spinner />,
  errorComponent: ({ error }) => <ErrorDisplay error={error} />,
  component: PostComponent,
})

createServerFn

const serverFn = createServerFn({ method: 'GET' })
  .validator(z.object({ id: z.string() }))
  .middleware([authMiddleware])
  .handler(async ({ data, context }) => {
    // context.user available from middleware
    return db.find(data.id)
  })

// Call from client or loader:
const result = await serverFn({ data: { id: '123' } })

Middleware

import { createMiddleware } from '@tanstack/react-start'

export const authMiddleware = createMiddleware()
  .server(async ({ next, context }) => {
    const session = await getSession(context.request)
    if (!session) throw redirect({ to: '/login' })
    return next({ context: { user: session.user } })
  })

Chain: serverFn.middleware([logger, auth, rateLimit])

API Routes

// src/routes/api/health.ts
import { createAPIFileRoute } from '@tanstack/react-start/api'
export const APIRoute = createAPIFileRoute('/api/health')({
  GET: () => new Response(JSON.stringify({ ok: true })),
  POST: async ({ request }) => {
    const body = await request.json()
    return new Response(JSON.stringify(body))
  },
})

SSR Configuration

Default: client-side SPA. Opt-in SSR per route:

export const Route = createFileRoute('/')({
  ssr: true,           // enable SSR for this route
  ssr: { streaming: true }, // enable streaming SSR
})

Deploy Targets (Nitro Presets)

node-server, cloudflare-workers, cloudflare-pages, vercel, netlify, deno, bun, aws-lambda

Key Packages

  • @tanstack/react-start — framework
  • @tanstack/react-router — routing (bundled)
  • @tanstack/react-query — data fetching (optional but recommended)
  • vinxi / nitro — server runtime (bundled)