Skip to main content
rule

tanstack-start-cursorrules-prompt-file — Cursor rule

Guides Cursor when building with TanStack Start, covering server functions, file-based routes, SSR, and streamed data.

Install into Cursor · Manually: put the files in place All methods and platforms ↓
.cursor/rules/tanstack-start-cursorrules-prompt-file.mdc
Open on GitHub

What tanstack-start-cursorrules-prompt-file does

This rule gives Cursor project guidance for TanStack Start, TanStack Router, and React. It covers file-based routing, createServerFn handlers with Zod input validation, route loaders, and mutations using TanStack Query. For most server-side logic it points to server functions; raw HTTP routes are reserved for cases such as webhooks and third-party integrations.

The guidance also shows how to stream non-critical data with defer() and <Suspense>, guard routes with beforeLoad, and read cookies or headers from server context. Deployment presets are configured in app.config.ts; listed targets include Node.js, Vercel, Netlify, Bun, and Cloudflare Pages. Client components should not access process.env, so keep server-only variables on the server.

For Cursor, place the rule at .cursor/rules/tanstack-start-cursorrules-prompt-file.mdc. Its glob covers **/*, while alwaysApply: false means it is not applied unconditionally.

What it helps with

  • structure file-based routes in a TanStack Start app
  • define a Zod-validated server function
  • load route data and handle mutations with TanStack Query
  • stream non-critical results with defer() and <Suspense>
  • guard routes and read cookies in server context

Example prompts for the agent

  • Create a server function that fetches a post by ID and validates its input with Zod.
  • Add a /posts/$postId route that loads the post through a server function.
  • Stream comments with defer() and render them inside <Suspense>.

How to install tanstack-start-cursorrules-prompt-file

Manually: put the files in place

.cursor/rules/tanstack-start-cursorrules-prompt-file.mdc

Frontmatter: description, globs, alwaysApply

Step by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules

Questions about tanstack-start-cursorrules-prompt-file

How do I install tanstack-start-cursorrules-prompt-file in Cursor?

Place the rule file at .cursor/rules/tanstack-start-cursorrules-prompt-file.mdc in your project.

What does tanstack-start-cursorrules-prompt-file do?

It guides Cursor through TanStack Start patterns, including server functions, file-based routes, SSR, and streaming data.

When should I use an API route instead of a server function?

The rule recommends createServerFn for most server-side logic. It uses createAPIFileRoute for raw HTTP endpoints such as webhooks and third-party integrations.

Source text

tanstack-start-cursorrules-prompt-file.mdc · CC0-1.0
---
description: "Cursor rules for TanStack Start full-stack React framework including server functions, API routes, streaming with defer(), SSR, and multi-platform deployment."
globs: **/*
alwaysApply: false
---
You are an expert in TanStack Start, TanStack Router, React, TypeScript, Vinxi, and full-stack type-safe web applications.

# TanStack Start Guidelines

## What is TanStack Start
TanStack Start is a full-stack React framework built on top of TanStack Router and Vinxi (Vite + Nitro). It provides SSR, streaming, server functions, and API routes with end-to-end type safety.

## Core Principles
- TanStack Start is file-based routing via TanStack Router — all routing conventions apply
- Server Functions (`createServerFn`) are the primary way to run server-side logic
- Full-stack type safety: server function inputs/outputs are typed end-to-end
- Streaming and Suspense are first-class — use them for progressive rendering
- Start is NOT an API-first framework — server functions replace REST endpoints for most use cases

## Project Structure
```
src/
  routes/
    __root.tsx          ← Root layout with HTML shell
    index.tsx           ← Home route
    posts/
      index.tsx
      $postId.tsx
  server/
    functions/          ← Server functions (recommended organization)
      posts.ts
      auth.ts
  lib/
    db.ts               ← Database client
    auth.ts             ← Auth utilities
app.config.ts           ← TanStack Start / Vinxi config
```

## app.config.ts
```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 Setup
```tsx
// src/routes/__root.tsx
import { createRootRoute, ScrollRestoration, Scripts, Outlet } from '@tanstack/react-router'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { TanStackRouterDevtools } from '@tanstack/router-devtools'

export const Route = createRootRoute({
  component: RootComponent,
})

function RootComponent() {
  return (
    <html lang="en">
      <head />
      <body>
        <Outlet />
        <ScrollRestoration />
        <Scripts />
        {process.env.NODE_ENV === 'development' && (
          <>
            <TanStackRouterDevtools />
            <ReactQueryDevtools />
          </>
        )}
      </body>
    </html>
  )
}
```

## Server Functions
- Use `createServerFn` to define functions that always run on the server
- Validate inputs with Zod using `.validator()`
- Use `.handler()` for the implementation
- Server functions are called like regular async functions from components or loaders
```ts
// src/server/functions/posts.ts
import { createServerFn } from '@tanstack/start'
import { z } from 'zod'

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, context }) => {
    // context has access to request headers, cookies, etc.
    return db.post.create({ data })
  })
```

## Using Server Functions in Routes
```tsx
// src/routes/posts/$postId.tsx
import { createFileRoute } from '@tanstack/react-router'
import { getPost } from '../../server/functions/posts'

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

function PostDetail() {
  const post = Route.useLoaderData()
  return <article><h1>{post.title}</h1></article>
}
```

## Mutations with Server Functions
- Call server functions directly in event handlers or via TanStack Query mutations
```tsx
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { createPost } from '../../server/functions/posts'

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

  return (
    <form onSubmit={(e) => {
      e.preventDefault()
      const fd = new FormData(e.currentTarget)
      mutation.mutate({ title: fd.get('title') as string, body: fd.get('body') as string })
    }}>
      <input name="title" />
      <textarea name="body" />
      <button type="submit" disabled={mutation.isPending}>
        {mutation.isPending ? 'Creating...' : 'Create'}
      </button>
    </form>
  )
}
```

## API Routes
- Use `createAPIFileRoute` for raw HTTP endpoints (webhooks, third-party integrations)
- Place in `src/routes/api/` directory
```ts
// src/routes/api/webhook.ts
import { createAPIFileRoute } from '@tanstack/start/api'

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

## Streaming & Suspense
- Use `defer()` to stream non-critical data after the initial render
- Wrap deferred data consumers in `<Suspense>`
```tsx
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 (deferred)
    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}>
          {(resolved) => <CommentsList comments={resolved} />}
        </Await>
      </Suspense>
    </div>
  )
}
```

## Authentication
- Read cookies/headers in server functions using TanStack Start's server context
- Use `beforeLoad` in routes for auth guards
```ts
import { getWebRequest } from '@tanstack/start/server'

export const getSession = createServerFn().handler(async () => {
  const request = getWebRequest()
  const sessionToken = getCookie(request, 'session')
  return validateSession(sessionToken)
})
```

## Deployment Targets
- `node-server` — default Node.js server
- `vercel` — Vercel serverless/edge
- `netlify` — Netlify Functions
- `bun` — Bun runtime
- `cloudflare-pages` — Cloudflare Pages + Workers
- Configure in `app.config.ts` under `server.preset`

## Environment Variables
- Access server-only vars directly from `process.env` inside server functions
- Use Vite's `import.meta.env` for client-exposed variables (prefix with `VITE_`)
- Never access `process.env` in client components

## TanStack Query Integration
- Provide `QueryClient` via router context for loader-level prefetching
- Use `ensureQueryData` in loaders to populate cache before render
- This eliminates loading states for route-level data fetching

© PatrickJS · CC0-1.0 · PatrickJS/awesome-cursorrules

Similar IDE rules

All IDE rules for Frontend and UI →

From the same set210

toss-style-design-system This Cursor rule guides the agent toward restrained product interfaces with clear hierarchy, grayscale structure, and limited accent color. Use it when editing UI components or styles. ★ 41,024repo stars tokrepo-agent-discovery-cursorrules-prompt-file This Cursor rule makes the agent search TokRepo for existing skills, prompts and MCP configs before writing new ones, and verify every candidate before install. ★ 41,024repo stars tensorflow-deep-learning This rule guides Cursor through TensorFlow project structure, data checks, model training, evaluation, and export. Use it when you want these practices applied to your Python files and notebooks. ★ 41,024repo stars tauri-svelte-typescript-guide-cursorrules-prompt-f A Cursor rule that sets how the agent writes desktop apps with Tauri: Svelte on the frontend, TypeScript for types. ★ 41,024repo stars tanstack-router A Cursor rule that sets agent conventions for TanStack Router v1: file-based routes, typed params and loader-based data fetching. ★ 41,024repo stars tanstack-query This Cursor rule guides TanStack Query v5 usage in React and TypeScript. Use it when building queries, mutations, pagination, or Suspense flows. ★ 41,024repo stars tanstack-query-v5-cursorrules-prompt-file A Cursor rule that tells the agent how to write TanStack Query v5 code: query keys, mutations, optimistic updates, Suspense and prefetching. ★ 41,024repo stars tailwind-shadcn-ui-integration-cursorrules-prompt- This Cursor rule guides Tailwind and shadcn/ui work, asking the assistant to outline a plan before writing readable TypeScript and Next.js code. ★ 41,024repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor