PluginBench
Rule

tanstack start

via PatrickJS/awesome-cursorrules

Full-stack React framework with type-safe server functions, file-based routing, and streaming via Vinxi/Nitro.

What is tanstack start?

TanStack Start combines TanStack Router with Vinxi (Vite + Nitro) to build full-stack React applications with end-to-end type safety. Use it when you need server-side logic, SSR, streaming data, and multi-platform deployment without separate REST APIs.

  • Define server functions with createServerFn() for type-safe client-server communication
  • Use file-based routing with loaders and search params via TanStack Router conventions
  • Stream non-critical data with defer() and Suspense for faster initial page loads
  • Deploy to Node.js, Vercel, Netlify, Bun, or Cloudflare Pages via configurable server presets
  • Create API routes for webhooks and raw HTTP endpoints alongside server functions
  • Access server-only environment variables in server functions and client-exposed vars via import.meta.env

Applies to

File patterns this rule matches.

["src/routes/**/*"
src/server/**/*
"app.config.ts"]
Rule definition (reference)

Source of truth, from the repository.

You are an expert in TanStack Start, TanStack Router, React, TypeScript, and full-stack type-safe web applications.

Core Principles

  • TanStack Start = TanStack Router + Vinxi (Vite + Nitro) for full-stack React
  • createServerFn is the primary way to run server-side logic with end-to-end type safety
  • All TanStack Router conventions apply — file-based routing, loaders, search params, etc.
  • Server functions replace REST endpoints for most use cases
  • Streaming + Suspense are first-class — use defer() for non-critical data

app.config.ts

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

export default defineConfig({
  vite: { plugins: [tsConfigPaths()] },
  server: {
    preset: 'node-server', // or: 'vercel', 'netlify', 'bun', 'cloudflare-pages'
  },
})

Root Route HTML Shell

// src/routes/__root.tsx
export const Route = createRootRoute({
  component: () => (
    <html lang="en">
      <head />
      <body>
        <Outlet />
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  ),
})

Server Functions

// src/server/functions/posts.ts
export const getPost = createServerFn()
  .validator(z.object({ id: z.string() }))
  .handler(async ({ data }) => {
    const post = await db.post.findUnique({ where: { id: data.id } })
    if (!post) throw new Error('Post not found')
    return post
  })

export const createPost = createServerFn()
  .validator(z.object({ title: z.string().min(1), body: z.string() }))
  .handler(async ({ data }) => db.post.create({ data }))

Using Server Functions in Routes

export const Route = createFileRoute('/posts/$postId')({
  loader: ({ params }) => getPost({ data: { id: params.postId } }),
  component: PostDetail,
})

Mutations with Server Functions

const mutation = useMutation({
  mutationFn: (input: { title: string; body: string }) => createPost({ data: input }),
  onSuccess: () => queryClient.invalidateQueries({ queryKey: ['posts'] }),
})

API Routes (for webhooks / raw HTTP)

// src/routes/api/webhook.ts
export const Route = createAPIFileRoute('/api/webhook')({
  POST: async ({ request }) => {
    const body = await request.json()
    return Response.json({ received: true })
  },
})

Streaming with defer()

export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => {
    const post = await getPost({ data: { id: params.postId } })  // awaited = critical
    const comments = getComments({ data: { postId: params.postId } })  // not awaited
    return { post, comments: defer(comments) }
  },
  component: PostDetail,
})

function PostDetail() {
  const { post, comments } = Route.useLoaderData()
  return (
    <div>
      <h1>{post.title}</h1>
      <Suspense fallback={<CommentsSkeleton />}>
        <Await promise={comments}>{(c) => <CommentsList comments={c} />}</Await>
      </Suspense>
    </div>
  )
}

Environment Variables

  • Access server-only vars via process.env inside server functions only
  • Use import.meta.env.VITE_* for client-exposed variables
  • Never access process.env in client components

Deployment Targets

Configure server.preset in app.config.ts:

  • node-server — default Node.js
  • vercel — Vercel serverless/edge
  • netlify — Netlify Functions
  • bun — Bun runtime
  • cloudflare-pages — Cloudflare Pages + Workers

Related rules

Senior full-stack TypeScript, React, Node.js guidance with clean architecture, testing, and WHY-oriented reasoning.

**/*
41k
via PatrickJS/awesome-cursorrules

Quantitative factor research skills for designing, evaluating, and mining alpha factors in equities markets.

**/*
41k
via PatrickJS/awesome-cursorrules

Android development with Jetpack Compose, clean architecture, and Material Design 3.

**/*
41k
via PatrickJS/awesome-cursorrules

Angular development with Novo Elements UI library using standalone components.

**/*
41k
via PatrickJS/awesome-cursorrules

Expert Angular 18 + TypeScript development with Jest, emphasizing clean code and performance.

**/*
41k
via PatrickJS/awesome-cursorrules

Manage Kubernetes clusters, add-ons, stacks, and credentials via the Ankra CLI platform.

**/*.sh +5
41k
via PatrickJS/awesome-cursorrules