Claude Code Plugins

Community-maintained marketplace

Feedback

TanStack Router

@jezweb/claude-skills
96
3

|

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name TanStack Router
description Build type-safe, file-based React routing with TanStack Router. Supports client-side navigation, route loaders, and TanStack Query integration. Use when implementing file-based routing patterns, building SPAs with TypeScript routing, or troubleshooting devtools dependency errors, type safety issues, or Vite bundling problems.

TanStack Router

Type-safe, file-based routing for React SPAs with route-level data loading and TanStack Query integration


Quick Start

Last Updated: 2025-11-28 Version: @tanstack/react-router@1.139.10

npm install @tanstack/react-router @tanstack/router-devtools
npm install -D @tanstack/router-plugin

Vite Config (TanStackRouterVite MUST come before react()):

// vite.config.ts
import { TanStackRouterVite } from '@tanstack/router-plugin/vite'

export default defineConfig({
  plugins: [TanStackRouterVite(), react()], // Order matters!
})

File Structure:

src/routes/
├── __root.tsx         → createRootRoute() with <Outlet />
├── index.tsx          → createFileRoute('/')
└── posts.$postId.tsx  → createFileRoute('/posts/$postId')

App Setup:

import { createRouter, RouterProvider } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen' // Auto-generated by plugin

const router = createRouter({ routeTree })
<RouterProvider router={router} />

Core Patterns

Type-Safe Navigation (routes auto-complete, params typed):

<Link to="/posts/$postId" params={{ postId: '123' }} />
<Link to="/invalid" /> // ❌ TypeScript error

Route Loaders (data fetching before render):

export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => ({ post: await fetchPost(params.postId) }),
  component: ({ useLoaderData }) => {
    const { post } = useLoaderData() // Fully typed!
    return <h1>{post.title}</h1>
  },
})

TanStack Query Integration (prefetch + cache):

const postOpts = (id: string) => queryOptions({
  queryKey: ['posts', id],
  queryFn: () => fetchPost(id),
})

export const Route = createFileRoute('/posts/$postId')({
  loader: ({ context: { queryClient }, params }) =>
    queryClient.ensureQueryData(postOpts(params.postId)),
  component: () => {
    const { postId } = Route.useParams()
    const { data } = useQuery(postOpts(postId))
    return <h1>{data.title}</h1>
  },
})

Known Issues & Solutions

Issue #1: Devtools Dependency Resolution

  • Error: Build fails with @tanstack/router-devtools-core not found
  • Fix: npm install @tanstack/router-devtools

Issue #2: Vite Plugin Order (CRITICAL)

  • Error: Routes not auto-generated, routeTree.gen.ts missing
  • Fix: TanStackRouterVite MUST come before react() in plugins array
  • Why: Plugin processes route files before React compilation

Issue #3: Type Registration Missing

  • Error: <Link to="..."> not typed, no autocomplete
  • Fix: Import routeTree from ./routeTree.gen in main.tsx to register types

Issue #4: Loader Not Running

  • Error: Loader function not called on navigation
  • Fix: Ensure route exports Route constant: export const Route = createFileRoute('/path')({ loader: ... })

Issue #5: Memory Leak with TanStack Form

  • Error: Production crashes when using TanStack Form + Router
  • Source: GitHub Issue #5734 (known issue, unfixed as of v1.139)
  • Workaround: Use React Hook Form or Formik instead

Cloudflare Workers Integration

Vite Config (add @cloudflare/vite-plugin):

import { cloudflare } from '@cloudflare/vite-plugin'

export default defineConfig({
  plugins: [TanStackRouterVite(), react(), cloudflare()],
})

API Routes Pattern (fetch from Workers backend):

// Worker: functions/api/posts.ts
export async function onRequestGet({ env }) {
  const { results } = await env.DB.prepare('SELECT * FROM posts').all()
  return Response.json(results)
}

// Router: src/routes/posts.tsx
export const Route = createFileRoute('/posts')({
  loader: async () => fetch('/api/posts').then(r => r.json()),
})

Related Skills: tanstack-query (data fetching), cloudflare-worker-base (API backend), tailwind-v4-shadcn (UI)