Agent Skills

tanstack-start

Full-stack React framework powered by TanStack Router with SSR, streaming, server functions, and deployment to any hosting provider.

Install

npx skills add https://github.com/tanstack-skills/tanstack-skills --skill tanstack-start
SKILL.md

TanStack Start Skills

Overview

TanStack Start is a full-stack React framework built on TanStack Router, powered by Vite and Nitro (via Vinxi). It provides server-side rendering, streaming, server functions (RPC), middleware, API routes, and deploys to any platform via Nitro presets.

Package: @tanstack/react-start Router Plugin: @tanstack/router-plugin Build Tool: Vinxi (Vite + Nitro) Status: RC (Release Candidate) RSC Support: React Server Components support is in active development and will land as a non-breaking v1.x addition

Installation & Project Setup

npx @tanstack/cli create my-app
# Or manually:
npm install @tanstack/react-start @tanstack/react-router react react-dom
npm install -D @tanstack/router-plugin typescript vite vite-tsconfig-paths

Project Structure

my-app/
  app/
    routes/
      __root.tsx          # Root layout
      index.tsx           # / route
      posts.$postId.tsx   # /posts/:postId
      api/
        users.ts          # /api/users API route
    client.tsx            # Client entry
    router.tsx            # Router creation
    ssr.tsx               # SSR entry
    routeTree.gen.ts      # Auto-generated route tree
  app.config.ts           # TanStack Start config
  tsconfig.json
  package.json

Configuration (app.config.ts)

import { defineConfig } from '@tanstack/react-start/config'
import viteTsConfigPaths from 'vite-tsconfig-paths'

export default defineConfig({
  vite: {
    plugins: [
      viteTsConfigPaths({ projects: ['./tsconfig.json'] }),
    ],
  },
  server: {
    preset: 'node-server', // 'vercel' | 'netlify' | 'cloudflare-pages' | etc.
  },
  tsr: {
    appDirectory: './app',
    routesDirectory: './app/routes',
    generatedRouteTree: './app/routeTree.gen.ts',
  },
})

Server Functions (createServerFn)

Server functions provide type-safe RPC calls between client and server.

Basic Server Functions

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

// GET (data fetching, cacheable)
const getUsers = createServerFn()
  .handler(async () => {
    const users = await db.query.users.findMany()
    return users
  })

// POST (mutations, side effects)
const createUser = createServerFn({ method: 'POST' })
  .validator((data: { name: string; email: string }) => data)
  .handler(async ({ data }) => {
    const user = await db.insert(users).values(data).returning()
    return user
  })

With Zod Validation

import { z } from 'zod'

const updateUser = createServerFn({ method: 'POST' })
  .validator(
    z.object({
      id: z.string(),
      name: z.string().min(1),
      email: z.string().email(),
    })
  )
  .handler(async ({ data }) => {
    // data is fully typed: { id: string; name: string; email: string }
    return await db.update(users).set(data).where(eq(users.id, data.id))
  })

Middleware

Creating Middleware

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

const loggingMiddleware = createMiddleware().handler(async ({ next }) => {
  console.log('Request started')
  const result = await next()
  console.log('Request completed')
  return result
})

Auth Middleware with Context

const authMiddleware = createMiddleware().handler(async ({ next }) => {
  const request = getWebRequest()
  const session = await getSession(request)

  if (!session?.user) {
    throw redirect({ to: '/login' })
  }

  // Pass typed context to handler
  return next({ context: { user: session.user } })
})

Chaining Middleware

const adminMiddleware = createMiddleware()
  .middleware([authMiddleware])
  .handler(async ({ next, context }) => {
    // context.user is typed from authMiddleware
    if (context.user.role !== 'admin') {
      throw redirect({ to: '/unauthorized' })
    }
    return next({ context: { isAdmin: true } })
  })

// Usage
const adminAction = createServerFn({ method: 'POST' })
  .middleware([adminMiddleware])
  .handler(async ({ context }) => {
    // context: { user: User; isAdmin: boolean }
    return { success: true }
  })

API Routes (Server Routes)

// app/routes/api/users.ts
import { createAPIFileRoute } from '@tanstack/react-start/api'

export const APIRoute = createAPIFileRoute('/api/users')({
  GET: async ({ request }) => {
    const users = await db.query.users.findMany()
    return Response.json(users)
  },
  POST: async ({ request }) => {
    const body = await request.json()
    const user = await db.insert(users).values(body).returning()
    return new Response(JSON.stringify(user), { status: 201 })
  },
})

SSR Strategies

Streaming SSR (Default)

export const Route = createFileRoute('/dashboard')({
  loader: async () => ({
    criticalData: await fetchCriticalData(),
    deferredData: defer(fetchSlowData()),
  }),
  component: Dashboard,
})

function Dashboard() {
  const { criticalData, deferredData } = Route.useLoaderData()
  return (
    <div>
      <CriticalSection data={criticalData} />
      <Suspense fallback={<Loading />}>
        <Await promise={deferredData}>
          {(data) => <SlowSection data={data} />}
        </Await>
      </Suspense>
    </div>
  )
}

Deployment

Supported Platforms (Nitro Presets)

// app.config.ts
export default defineConfig({
  server: {
    preset: 'node-server',        // Self-hosted Node.js
    // preset: 'vercel',          // Vercel
    // preset: 'netlify',         // Netlify
    // preset: 'cloudflare-pages', // Cloudflare Pages
    // preset: 'aws-lambda',      // AWS Lambda
    // preset: 'deno-server',     // Deno Deploy
    // preset: 'bun',             // Bun
  },
})

Best Practices

  1. Use validators for all server function inputs - runtime safety and TypeScript inference
  2. Compose middleware for cross-cutting concerns (auth, logging, rate limiting)
  3. Use createServerFn GET for data fetching (cacheable, preloadable)
  4. Use createServerFn POST for mutations and side effects
  5. Use beforeLoad for route-level auth guards
  6. Use defer() for non-critical data to improve TTFB
  7. Set defaultPreload: 'intent' on the router for instant navigation
  8. Co-locate server functions with the routes that use them

Common Pitfalls

  • Server functions cannot close over client-side variables (they're extracted to separate bundles)
  • Data returned from server functions must be serializable
  • Forgetting await in loaders leads to streaming issues
  • Importing server-only code in client bundles causes build errors
  • Missing declare module '@tanstack/react-router' loses all type safety

Related skills

vercel-react-best-practicesvercel-labs751KReact and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.vercel-composition-patternsvercel-labs361KReact composition patterns that scale. Use when refactoring components with boolean prop proliferation, building flexible component libraries, or designing reusable APIs. Triggers on tasks involving compound components, render props, context providers, or component architecture. Includes React 19 API changes.vercel-react-view-transitionsvercel-labs135KGuide for implementing smooth, native-feeling animations using React's View Transition API (`<ViewTransition>` component, `addTransitionType`, and CSS view transition pseudo-elements). Use this skill whenever the user wants to add page transitions, animate route changes, create shared element animations, animate enter/exit of components, animate list reorder, implement directional (forward/back) navigation animations, or integrate view transitions in Next.js. Also use when the user mentions viewpick-ui-libraryemilkowalski124KPick the right library for a given frontend task from a curated, opinionated list — numbers, OTP inputs, charts, command menus, virtualization, drag and drop, toasts, state, styling, and more. Only runs when explicitly invoked; it does not trigger on its own.

Search skills and MCP servers

Fuzzy search across 23,137 skills and servers