Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ By creating a `.cursorrules` file in your project's root directory, you can leve
- [Python (Flask JSON Guide)](./rules/python-flask-json-guide-cursorrules-prompt-file/.cursorrules) - Cursor rules for Python Flask development with JSON guide.
- [Python LLM & ML Workflow](./rules/python-llm-ml-workflow-cursorrules-prompt-file/.cursorrules) - Cursor rules for Python LLM & ML development with workflow integration.
- [Salesforce (Apex)](./rules/salesforce-apex-cursorrules-prompt-file/.cursorrules.txt) - Cursor rules for Salesforce development with Apex integration.
- [TanStack Start](./rules/tanstack-start-cursorrules-prompt-file/.cursorrules) - Cursor rules for TanStack Start full-stack React framework including server functions, API routes, streaming with defer(), SSR, and multi-platform deployment.
- [TypeScript (NestJS Best Practices)](./rules/typescript-nestjs-best-practices-cursorrules-promp/.cursorrules) - Cursor rules for TypeScript development with NestJS best practices.
- [TYPO3 CMS Extension](./rules/typo3cms-extension-cursorrules-prompt-file/.cursorrules) - Cursor rules for TYPO3 CMS development with extension integration.
- [WordPress (PHP, Guzzle, Gutenberg)](./rules/wordpress-php-guzzle-gutenberg-cursorrules-prompt-/.cursorrules) - Cursor rules for WordPress development with PHP, Guzzle, and Gutenberg integration.
Expand Down
124 changes: 124 additions & 0 deletions rules-new/tanstack-start.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
---
description: TanStack Start full-stack React framework using server functions, API routes, SSR, streaming with defer(), and multi-platform deployment via Vinxi/Nitro
globs: ["src/routes/**/*", "src/server/**/*", "app.config.ts"]
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Frontmatter globs is expressed as a YAML inline array here, but other .mdc files in rules-new/ use a plain string/comma-separated pattern for globs (e.g. rules-new/nextjs.mdc). To avoid inconsistent parsing/ingestion, consider switching this to the same string format used elsewhere in the repo.

Suggested change
globs: ["src/routes/**/*", "src/server/**/*", "app.config.ts"]
globs: src/routes/**/*, src/server/**/*, app.config.ts

Copilot uses AI. Check for mistakes.
alwaysApply: false
---

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

## Server Functions
```ts
// 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
```tsx
export const Route = createFileRoute('/posts/$postId')({
loader: ({ params }) => getPost({ data: { id: params.postId } }),
component: PostDetail,
})
```

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

## API Routes (for webhooks / raw HTTP)
```ts
// 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()
```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
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
228 changes: 228 additions & 0 deletions rules/tanstack-start-cursorrules-prompt-file/.cursorrules
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
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' && (
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the Root Route example, process.env.NODE_ENV is used inside a route component. This conflicts with the later guidance in this same file (“Never access process.env in client components”) and can also fail in Vite-based client bundles where process isn’t defined. Prefer import.meta.env.DEV/import.meta.env.MODE, or gate devtools via a server-derived flag passed to the client.

Suggested change
{process.env.NODE_ENV === 'development' && (
{import.meta.env.DEV && (

Copilot uses AI. Check for mistakes.
<>
<TanStackRouterDevtools />
<ReactQueryDevtools />
</>
)}
Comment on lines +68 to +73
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In TanStack Start (Vite-based), what is the recommended way to gate dev-only UI inside route components: process.env.NODE_ENVorimport.meta.env.DEV?

💡 Result:

In TanStack Start (Vite-based), the recommended way to gate dev-only UI inside route components is import.meta.env.DEV.

Citations:


🏁 Script executed:

# First, find the .cursorrules file
find . -name ".cursorrules" -type f

Repository: PatrickJS/awesome-cursorrules

Length of output: 11792


🏁 Script executed:

# Read the relevant lines from the .cursorrules file
# Get lines around 68-73 and line 223
if [ -f "rules/tanstack-start-cursorrules-prompt-file/.cursorrules" ]; then
  echo "=== Lines 65-75 (context around line 68-73) ==="
  sed -n '65,75p' "rules/tanstack-start-cursorrules-prompt-file/.cursorrules" | cat -n
  echo ""
  echo "=== Lines 220-225 (context around line 223) ==="
  sed -n '220,225p' "rules/tanstack-start-cursorrules-prompt-file/.cursorrules" | cat -n
fi

Repository: PatrickJS/awesome-cursorrules

Length of output: 814


Fix contradictory env guidance in client-rendered example.

Line 223 states "Never access process.env in client components," but Lines 68-73 use process.env.NODE_ENV in the RootComponent. This violates the stated guideline. In TanStack Start (Vite-based), use import.meta.env.DEV for dev-only rendering checks.

Suggested doc fix
-        {process.env.NODE_ENV === 'development' && (
+        {import.meta.env.DEV && (
           <>
             <TanStackRouterDevtools />
             <ReactQueryDevtools />
           </>
         )}

Also applies to: 220-223

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rules/tanstack-start-cursorrules-prompt-file/.cursorrules` around lines 68 -
73, The client RootComponent currently checks process.env.NODE_ENV to
conditionally render TanStackRouterDevtools and ReactQueryDevtools which
contradicts the guideline to never access process.env in client components;
replace that check by using the Vite/TanStack-safe flag import.meta.env.DEV in
the RootComponent (the conditional around TanStackRouterDevtools and
ReactQueryDevtools) so dev-only rendering uses import.meta.env.DEV instead of
process.env.NODE_ENV.

</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
19 changes: 19 additions & 0 deletions rules/tanstack-start-cursorrules-prompt-file/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# TanStack Start Cursor Rules

Cursor rules for TanStack Start — the full-stack React framework built on TanStack Router and Vinxi. Covers server functions, API routes, streaming, SSR, authentication, and multi-platform deployment.

## What's covered
- Project structure and `app.config.ts` setup
- Root route HTML shell configuration
- `createServerFn` with Zod validation
- Using server functions in loaders and mutation handlers
- Raw API routes with `createAPIFileRoute`
- Streaming with `defer()` and Suspense
- Auth via server-side cookie/session access
- Deployment targets (Vercel, Netlify, Cloudflare, Bun, Node)
- TanStack Query integration for cache-first data loading

## Author
Created by [usm4nhafeez](https://github.com/usm4nhafeez)

Contributed to [awesome-cursorrules](https://github.com/PatrickJS/awesome-cursorrules)
Loading
Loading