diff --git a/_artifacts/skill_tree.yaml b/_artifacts/skill_tree.yaml
index b5ce76f547..ec38a04bdd 100644
--- a/_artifacts/skill_tree.yaml
+++ b/_artifacts/skill_tree.yaml
@@ -135,7 +135,6 @@ skills:
for auth state.
requires:
- 'router-core'
- - 'router-core/data-loading'
sources:
- 'TanStack/router:docs/router/guide/authenticated-routes.md'
- 'TanStack/router:docs/router/how-to/setup-authentication.md'
diff --git a/packages/react-router/skills/compositions/router-query/SKILL.md b/packages/react-router/skills/compositions/router-query/SKILL.md
index 89fba76b54..bcb2f939cd 100644
--- a/packages/react-router/skills/compositions/router-query/SKILL.md
+++ b/packages/react-router/skills/compositions/router-query/SKILL.md
@@ -1,14 +1,15 @@
---
-name: compositions/router-query
+name: router-query
description: >-
Integrating TanStack Router with TanStack Query: queryClient
in router context, ensureQueryData/prefetchQuery in loaders,
useSuspenseQuery in components, defaultPreloadStaleTime: 0,
setupRouterSsrQueryIntegration for SSR dehydration/hydration
and streaming, per-request QueryClient isolation.
-type: composition
-library: tanstack-router
-library_version: '1.166.2'
+metadata:
+ type: composition
+ library: tanstack-router
+ library_version: '1.166.2'
requires:
- router-core
- router-core/data-loading
diff --git a/packages/react-router/skills/lifecycle/migrate-from-react-router/SKILL.md b/packages/react-router/skills/lifecycle/migrate-from-react-router/SKILL.md
index c9f53358e6..fdc4f4c4e5 100644
--- a/packages/react-router/skills/lifecycle/migrate-from-react-router/SKILL.md
+++ b/packages/react-router/skills/lifecycle/migrate-from-react-router/SKILL.md
@@ -1,13 +1,14 @@
---
-name: lifecycle/migrate-from-react-router
+name: migrate-from-react-router
description: >-
Step-by-step migration from React Router v7 to TanStack Router:
route definition conversion, Link/useNavigate API differences,
useSearchParams to validateSearch + useSearch, useParams with from,
Outlet replacement, loader conversion, code splitting differences.
-type: lifecycle
-library: tanstack-router
-library_version: '1.166.2'
+metadata:
+ type: lifecycle
+ library: tanstack-router
+ library_version: '1.166.2'
requires:
- router-core
- react-router
diff --git a/packages/react-router/skills/react-router/SKILL.md b/packages/react-router/skills/react-router/SKILL.md
index 074f23e091..53f4135316 100644
--- a/packages/react-router/skills/react-router/SKILL.md
+++ b/packages/react-router/skills/react-router/SKILL.md
@@ -8,10 +8,11 @@ description: >-
Outlet, CatchBoundary, ErrorComponent. React-specific patterns
for hooks, providers, SSR hydration, and createLink with
forwardRef.
-type: framework
-library: tanstack-router
-library_version: '1.166.2'
-framework: react
+metadata:
+ type: framework
+ library: tanstack-router
+ library_version: '1.166.2'
+ framework: react
requires:
- router-core
sources:
@@ -24,8 +25,6 @@ sources:
This skill builds on router-core. Read [router-core](../../../router-core/skills/router-core/SKILL.md) first for foundational concepts.
-This skill covers the React-specific bindings, components, hooks, and setup for TanStack Router.
-
> **CRITICAL**: TanStack Router types are FULLY INFERRED. Never cast, never annotate inferred values.
> **CRITICAL**: TanStack Router is CLIENT-FIRST. Loaders run on the client by default, not on the server.
> **CRITICAL**: Do not confuse `@tanstack/react-router` with `react-router-dom`/`react-router`. They are completely different libraries with different APIs.
diff --git a/packages/react-start/skills/_artifacts/domain_map.yaml b/packages/react-start/skills/_artifacts/domain_map.yaml
index 297f9ccf04..4e790903a6 100644
--- a/packages/react-start/skills/_artifacts/domain_map.yaml
+++ b/packages/react-start/skills/_artifacts/domain_map.yaml
@@ -1,13 +1,13 @@
# domain_map.yaml
# Generated by skill-domain-discovery
# Library: TanStack Start
-# Version: 1.166.2
+# Version: 1.168.32
# Date: 2026-03-07
# Status: reviewed
library:
name: '@tanstack/react-start'
- version: '1.166.2'
+ version: '1.168.32'
repository: 'https://github.com/TanStack/router'
description: >-
Full-stack React framework built on TanStack Router and Vite. Adds
@@ -189,6 +189,15 @@ skills:
priority: HIGH
status: active
+ - mistake: 'Not using useServerFn for component calls'
+ mechanism: >-
+ Component calls need useServerFn so redirects and not-found
+ responses use the active router instead of falling through as
+ ordinary function results.
+ source: 'docs/start/framework/react/guide/server-functions.md'
+ priority: MEDIUM
+ status: active
+
- mistake: 'Generating Next.js or Remix server patterns'
mechanism: >-
Agents generate getServerSideProps, "use server" directives,
@@ -204,6 +213,39 @@ skills:
priority: CRITICAL
status: active
+ - mistake: 'Relying on a route guard to protect a server function'
+ mechanism: >-
+ beforeLoad protects route UX, but createServerFn exposes an
+ independently callable endpoint. Private handlers must enforce
+ authentication and authorization themselves or through middleware.
+ source: 'protocol-v4 evaluation'
+ priority: CRITICAL
+ status: active
+
+ - mistake: 'Self-fetching a relative API URL from an SSR loader'
+ mechanism: >-
+ Loaders also run on the server, where relative URLs may not have a
+ base. App-internal loaders should call a server function directly.
+ source: 'protocol-v4 evaluation'
+ priority: CRITICAL
+ status: active
+
+ - mistake: 'Mutating without invalidating cached loader data'
+ mechanism: >-
+ Local state can show a write that was not persisted or leave route
+ cache stale. Await the write, invalidate, and verify a fresh reload.
+ source: 'protocol-v4 evaluation'
+ priority: HIGH
+ status: active
+
+ - mistake: 'Treating typecheck as proof of output schema propagation'
+ mechanism: >-
+ A typed model can still be projected or serialized without the new
+ field. Assert the actual handler or HTTP payload at runtime.
+ source: 'protocol-v4 evaluation'
+ priority: CRITICAL
+ status: active
+
# ── Middleware and Context ───────────────────────────────────────
- name: 'Middleware'
slug: 'middleware'
@@ -354,6 +396,23 @@ skills:
priority: CRITICAL
status: active
+ - mistake: 'Hydration mismatches from env-dependent rendering'
+ mechanism: >-
+ Rendering different output from server-only environment state
+ causes the client hydration pass to disagree with the SSR HTML.
+ Transfer stable data or defer environment-dependent UI.
+ source: 'docs/start/framework/react/guide/execution-model.md'
+ priority: HIGH
+ status: active
+
+ - mistake: 'Using a relative URL in an isomorphic loader'
+ mechanism: >-
+ Browser fetch resolves relative URLs against the document, while an
+ SSR runtime may have no base URL. Use a server function boundary.
+ source: 'protocol-v4 evaluation'
+ priority: CRITICAL
+ status: active
+
# ── Server Routes ────────────────────────────────────────────────
- name: 'Server Routes'
slug: 'server-routes'
@@ -387,6 +446,39 @@ skills:
priority: MEDIUM
status: active
+ - mistake: 'Forgetting to await request body methods'
+ mechanism: >-
+ Request body readers return promises. Using request.json(),
+ request.text(), or request.formData() without await passes a promise
+ instead of the parsed request body.
+ source: 'docs/start/framework/react/guide/server-routes.md'
+ priority: MEDIUM
+ status: active
+
+ - mistake: 'Relying on page auth to protect a server route'
+ mechanism: >-
+ API handlers are directly callable and must authenticate and
+ authorize private reads and writes at the handler boundary.
+ source: 'protocol-v4 evaluation'
+ priority: CRITICAL
+ status: active
+
+ - mistake: 'Self-fetching a server route from an SSR loader'
+ mechanism: >-
+ A relative API URL can fail during SSR. Share one server-side service
+ between a server function and server route instead.
+ source: 'protocol-v4 evaluation'
+ priority: CRITICAL
+ status: active
+
+ - mistake: 'Omitting a field from serialized response output'
+ mechanism: >-
+ Typechecking does not inspect the runtime Response payload. Test the
+ serialized output when a schema changes.
+ source: 'protocol-v4 evaluation'
+ priority: CRITICAL
+ status: active
+
# ── Deployment and Rendering ─────────────────────────────────────
- name: 'Deployment'
slug: 'deployment'
diff --git a/packages/react-start/skills/_artifacts/skill_spec.md b/packages/react-start/skills/_artifacts/skill_spec.md
index ce016f4e03..f550196da8 100644
--- a/packages/react-start/skills/_artifacts/skill_spec.md
+++ b/packages/react-start/skills/_artifacts/skill_spec.md
@@ -18,10 +18,10 @@ TanStack Start is a full-stack React framework built on TanStack Router and Vite
| Skill | Type | Domain | What it covers | Failure modes |
| ------------------- | --------- | ------------------------ | ------------------------------------------------------- | ------------- |
| start-setup | core | project-setup | tanstackStart(), getRouter(), root route, entries | 3 |
-| server-functions | core | server-functions | createServerFn, validation, useServerFn, streaming | 4 |
+| server-functions | core | server-functions | createServerFn, validation, useServerFn, streaming | 8 |
| middleware | core | middleware-and-context | createMiddleware, context, global middleware, factories | 3 |
-| execution-model | core | execution-model | Isomorphic defaults, environment functions, env vars | 4 |
-| server-routes | core | server-routes | server property, HTTP handlers, createHandlers | 2 |
+| execution-model | core | execution-model | Isomorphic defaults, environment functions, env vars | 5 |
+| server-routes | core | server-routes | server property, HTTP handlers, createHandlers | 5 |
| deployment | core | deployment-and-rendering | Hosting, SSR modes, prerendering, SEO | 3 |
| server-components | sub-skill | deployment-and-rendering | React Server Components, cache ownership, selective SSR | 3 |
| react-start | framework | project-setup | React bindings, useServerFn, full setup | 3 |
@@ -37,14 +37,18 @@ TanStack Start is a full-stack React framework built on TanStack Router and Vite
| 2 | Enabling verbatimModuleSyntax in tsconfig | HIGH | docs/build-from-scratch |
| 3 | Missing Scripts component in root route | HIGH | docs/guide/routing |
-### server-functions (4 failure modes)
+### server-functions (8 failure modes)
-| # | Mistake | Priority | Source |
-| --- | --------------------------------------------------------------------------- | -------- | --------------------------- |
-| 1 | Putting server-only code in loaders instead of server functions | CRITICAL | maintainer interview |
-| 2 | Generating Next.js/Remix server patterns ("use server", getServerSideProps) | CRITICAL | maintainer interview |
-| 3 | Using dynamic imports for server functions | HIGH | docs/guide/server-functions |
-| 4 | Not using useServerFn for component calls | MEDIUM | docs/guide/server-functions |
+| # | Mistake | Priority | Source |
+| --- | --------------------------------------------------------------- | -------- | --------------------------- |
+| 1 | Putting server-only code in loaders instead of server functions | CRITICAL | maintainer interview |
+| 2 | Using dynamic imports for server functions | HIGH | docs/guide/server-functions |
+| 3 | Not using useServerFn for component calls | MEDIUM | docs/guide/server-functions |
+| 4 | Generating Next.js or Remix server patterns | CRITICAL | maintainer interview |
+| 5 | Relying on a route guard to protect a server function | CRITICAL | protocol-v4 evaluation |
+| 6 | Self-fetching a relative API URL from an SSR loader | CRITICAL | protocol-v4 evaluation |
+| 7 | Mutating without invalidating cached loader data | HIGH | protocol-v4 evaluation |
+| 8 | Treating typecheck as proof of output schema propagation | CRITICAL | protocol-v4 evaluation |
### middleware (3 failure modes)
@@ -54,7 +58,7 @@ TanStack Start is a full-stack React framework built on TanStack Router and Vite
| 2 | Confusing request vs server function middleware | MEDIUM | docs/guide/middleware |
| 3 | Wrong middleware method order | MEDIUM | docs/guide/middleware |
-### execution-model (4 failure modes)
+### execution-model (5 failure modes)
| # | Mistake | Priority | Source |
| --- | ------------------------------------------------- | -------- | -------------------------------- |
@@ -62,13 +66,17 @@ TanStack Start is a full-stack React framework built on TanStack Router and Vite
| 2 | Exposing secrets via module-level process.env | CRITICAL | docs/guide/execution-model |
| 3 | Using VITE\_ prefix for server secrets | CRITICAL | docs/guide/environment-variables |
| 4 | Hydration mismatches from env-dependent rendering | HIGH | docs/guide/execution-model |
+| 5 | Using a relative URL in an isomorphic loader | CRITICAL | protocol-v4 evaluation |
-### server-routes (2 failure modes)
+### server-routes (5 failure modes)
-| # | Mistake | Priority | Source |
-| --- | ---------------------------------------- | -------- | ------------------------ |
-| 1 | Duplicate route path resolution | MEDIUM | docs/guide/server-routes |
-| 2 | Forgetting to await request body methods | MEDIUM | docs/guide/server-routes |
+| # | Mistake | Priority | Source |
+| --- | ------------------------------------------------ | -------- | ------------------------ |
+| 1 | Duplicate path resolution for server routes | MEDIUM | docs/guide/server-routes |
+| 2 | Forgetting to await request body methods | MEDIUM | docs/guide/server-routes |
+| 3 | Relying on page auth to protect a server route | CRITICAL | protocol-v4 evaluation |
+| 4 | Self-fetching a server route from an SSR loader | CRITICAL | protocol-v4 evaluation |
+| 5 | Omitting a field from serialized response output | CRITICAL | protocol-v4 evaluation |
### deployment (3 failure modes)
diff --git a/packages/react-start/skills/_artifacts/skill_tree.yaml b/packages/react-start/skills/_artifacts/skill_tree.yaml
index 21f8c57c3a..3078228f73 100644
--- a/packages/react-start/skills/_artifacts/skill_tree.yaml
+++ b/packages/react-start/skills/_artifacts/skill_tree.yaml
@@ -1,7 +1,7 @@
# skills/_artifacts/start_skill_tree.yaml
library:
name: '@tanstack/react-start'
- version: '1.166.2'
+ version: '1.168.32'
repository: 'https://github.com/TanStack/router'
description: >-
Full-stack React framework built on TanStack Router and Vite.
diff --git a/packages/react-start/skills/lifecycle/migrate-from-nextjs/SKILL.md b/packages/react-start/skills/lifecycle/migrate-from-nextjs/SKILL.md
index c9c098addf..d59292bc4b 100644
--- a/packages/react-start/skills/lifecycle/migrate-from-nextjs/SKILL.md
+++ b/packages/react-start/skills/lifecycle/migrate-from-nextjs/SKILL.md
@@ -1,13 +1,14 @@
---
-name: lifecycle/migrate-from-nextjs
+name: migrate-from-nextjs
description: >-
Step-by-step migration from Next.js App Router to TanStack Start:
route definition conversion, API mapping, server function
conversion from Server Actions, middleware conversion, data
fetching pattern changes.
-type: lifecycle
-library: tanstack-start
-library_version: '1.166.2'
+metadata:
+ type: lifecycle
+ library: tanstack-start
+ library_version: '1.168.32'
requires:
- start-core
- react-start
diff --git a/packages/react-start/skills/react-start/SKILL.md b/packages/react-start/skills/react-start/SKILL.md
index c8dbfd4bbf..b0f69009e1 100644
--- a/packages/react-start/skills/react-start/SKILL.md
+++ b/packages/react-start/skills/react-start/SKILL.md
@@ -5,10 +5,11 @@ description: >-
StartServer, React-specific imports, re-exports from
@tanstack/react-router, full project setup with React, useServerFn
hook.
-type: framework
-library: tanstack-start
-library_version: '1.166.2'
-framework: react
+metadata:
+ type: framework
+ library: tanstack-start
+ library_version: '1.168.32'
+ framework: react
requires:
- start-core
sources:
@@ -18,9 +19,7 @@ sources:
# React Start (`@tanstack/react-start`)
-This skill builds on start-core. Read [start-core](../../../start-client-core/skills/start-core/SKILL.md) first for foundational concepts.
-
-This skill covers the React-specific bindings, setup, and patterns for TanStack Start.
+This is the React Start entry skill. Use the workflow below, then load only the package skill that owns the boundary you are changing. Do not read `start-core`, Router Core, and React Router manuals in full before starting.
For React Server Components patterns, see [react-start/server-components](./server-components/SKILL.md).
@@ -30,6 +29,16 @@ For React Server Components patterns, see [react-start/server-components](./serv
> **CRITICAL**: Types are FULLY INFERRED. Never cast, never annotate inferred values.
+## Full-Stack Workflow
+
+1. Define the route and component with `createFileRoute`.
+2. Put private or server-only reads and writes in `createServerFn`; call reads directly from loaders.
+3. Use `useServerFn` for component mutations, then invalidate the router or query cache after the write resolves.
+4. Enforce auth in every private server function or server route. Add `beforeLoad` separately for navigation UX.
+5. Run the initial SSR path, client navigation, mutation plus reload, direct anonymous endpoint request, runtime response assertion, type tests, and production build.
+
+Load `start-core/server-routes` instead of `server-functions` only when a raw HTTP endpoint is required. Load `router-core/*` only for the specific routing concern involved, such as params or search validation.
+
## Package API Surface
`@tanstack/react-start` re-exports everything from `@tanstack/start-client-core` plus:
diff --git a/packages/react-start/skills/react-start/server-components/SKILL.md b/packages/react-start/skills/react-start/server-components/SKILL.md
index eda716f32e..1d0b0b099f 100644
--- a/packages/react-start/skills/react-start/server-components/SKILL.md
+++ b/packages/react-start/skills/react-start/server-components/SKILL.md
@@ -1,5 +1,5 @@
---
-name: react-start/server-components
+name: server-components
description: >-
Implement, review, debug, and refactor TanStack Start React Server
Components in React 19 apps. Use when tasks mention
@@ -12,9 +12,10 @@ description: >-
migration from Next App Router RSC patterns. Do not use for
generic SSR or non-TanStack RSC frameworks except brief
comparison.
-type: sub-skill
-library: tanstack-start
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-start
+ library_version: '1.168.32'
requires:
- react-start
- start-core/server-functions
diff --git a/packages/router-core/skills/router-core/SKILL.md b/packages/router-core/skills/router-core/SKILL.md
index de11b17d28..cadb832037 100644
--- a/packages/router-core/skills/router-core/SKILL.md
+++ b/packages/router-core/skills/router-core/SKILL.md
@@ -5,9 +5,10 @@ description: >-
createRouter, createRoute, createRootRoute, createRootRouteWithContext,
addChildren, Register type declaration, route matching, route sorting,
file naming conventions. Entry point for all router skills.
-type: core
-library: tanstack-router
-library_version: '1.166.2'
+metadata:
+ type: core
+ library: tanstack-router
+ library_version: '1.171.15'
---
# TanStack Router Core
@@ -18,6 +19,8 @@ TanStack Router is a type-safe router for React and Solid with built-in SWR cach
> **CRITICAL**: TanStack Router is CLIENT-FIRST. Loaders run on the client by default, NOT server-only like Remix/Next.js. Do not confuse TanStack Router APIs with Next.js or React Router.
+Use this entry skill to choose one primary sub-skill. Do not load the full catalog. Load a second sub-skill only when the task crosses a real boundary, such as an authenticated loader that needs both `auth-and-guards` and `data-loading`.
+
## Sub-Skills
| Task | Sub-Skill |
@@ -66,6 +69,22 @@ Need server-side rendering?
→ router-core/ssr
```
+## Cross-Cutting Completion Checks
+
+For route refactors:
+
+1. Rename or move the route file; do not hand-edit the generated `createFileRoute` path.
+2. Regenerate `routeTree.gen.ts` with the configured Router plugin or CLI.
+3. Update links, redirects, `from` narrowing, params, and tests that reference the old route.
+4. Run type tests and a production build. A typecheck alone does not prove route generation or bundling works.
+
+For response schema changes:
+
+1. Update the source model and shared validation schema.
+2. Update the server function or API serializer so the field exists at runtime.
+3. Update loader and component consumers without casts.
+4. Assert the actual response payload in a unit or integration test. Typechecking cannot catch a serializer that omits the new field.
+
## Minimal Working Example
```tsx
@@ -136,4 +155,4 @@ The plugin auto-generates this string. If you rename a route file, the plugin up
## Version Note
-This skill targets `@tanstack/router-core` v1.166.2 and `@tanstack/react-router` v1.166.2. APIs are stable. Splat routes use `$` (not `*`); the `*` compat alias will be removed in v2.
+This skill targets `@tanstack/router-core` v1.171.15. Splat routes use `$` (not `*`); the `*` compat alias will be removed in v2.
diff --git a/packages/router-core/skills/router-core/auth-and-guards/SKILL.md b/packages/router-core/skills/router-core/auth-and-guards/SKILL.md
index 94d0090d78..71a87a2a3e 100644
--- a/packages/router-core/skills/router-core/auth-and-guards/SKILL.md
+++ b/packages/router-core/skills/router-core/auth-and-guards/SKILL.md
@@ -1,17 +1,17 @@
---
-name: router-core/auth-and-guards
+name: auth-and-guards
description: >-
Route protection with beforeLoad, redirect()/throw redirect(),
isRedirect helper, authenticated layout routes (_authenticated),
non-redirect auth (inline login), RBAC with roles and permissions,
auth provider integration (Auth0, Clerk, Supabase), router context
for auth state.
-type: sub-skill
-library: tanstack-router
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-router
+ library_version: '1.171.15'
requires:
- router-core
- - router-core/data-loading
sources:
- TanStack/router:docs/router/guide/authenticated-routes.md
- TanStack/router:docs/router/how-to/setup-authentication.md
@@ -377,7 +377,7 @@ export const Route = createFileRoute('/_authenticated')({
### CRITICAL: Route guards do not protect server functions
-A `beforeLoad` redirect protects the **route's UI**, not the **server functions** declared on it. `createServerFn` produces an RPC endpoint reachable by direct POST regardless of which route renders the calling UI. An attacker doesn't have to load `/_authenticated/orders` — they can curl the RPC endpoint directly.
+A `beforeLoad` redirect protects the **route's UI**, not the **server functions** declared on it. `createServerFn` produces an RPC endpoint reachable directly with its declared HTTP method regardless of which route renders the calling UI. An attacker doesn't have to load `/_authenticated/orders` — they can call this GET RPC endpoint directly.
```tsx
// WRONG — handler has no auth check; the route guard doesn't help
@@ -410,6 +410,10 @@ const getMyOrders = createServerFn({ method: 'GET' })
Rule of thumb: every `createServerFn`, server route, or API endpoint that touches user data needs `authMiddleware` (or an equivalent in-handler check). The route guard is for the page experience; the endpoint guard is for the data. See [start-core/auth-server-primitives](../../../../start-client-core/skills/start-core/auth-server-primitives/SKILL.md) for the full session/middleware pattern.
+### CRITICAL: The anonymous destination can still disclose protected data
+
+Protect the entire anonymous response, not only the API call. A public login or unauthorized page still leaks data if its title, copy, search params, or serialized loader state names the protected user, tenant, record, or resource. Test a direct anonymous request and follow redirects. Assert that the handler rejects before reading private data, no protected loader runs, the final HTML and serialized state contain no protected identity, and the redirect contains only a sanitized relative return URL.
+
### HIGH: Auth check in component instead of beforeLoad
Component-level auth checks cause a **flash of protected content** before the redirect:
@@ -435,8 +439,6 @@ export const Route = createFileRoute('/_authenticated/dashboard')({
})
```
-`beforeLoad` runs before any component rendering and before the loader. It completely prevents the flash.
-
### HIGH: Not re-throwing redirects in try/catch
`redirect()` works by throwing. If `beforeLoad` has a try/catch, the redirect gets swallowed:
@@ -490,8 +492,6 @@ export const Route = createFileRoute('/_authenticated')({
Place protected routes as children of the `_authenticated` layout route. Public routes (login, home, etc.) live outside it.
----
-
## Cross-References
- See also: **router-core/data-loading/SKILL.md** — `beforeLoad` runs before `loader`; auth context flows into loader via route context
diff --git a/packages/router-core/skills/router-core/code-splitting/SKILL.md b/packages/router-core/skills/router-core/code-splitting/SKILL.md
index 8d1ba4e7a5..aac9098121 100644
--- a/packages/router-core/skills/router-core/code-splitting/SKILL.md
+++ b/packages/router-core/skills/router-core/code-splitting/SKILL.md
@@ -1,13 +1,14 @@
---
-name: router-core/code-splitting
+name: code-splitting
description: >-
Automatic code splitting (autoCodeSplitting), .lazy.tsx convention,
createLazyFileRoute, createLazyRoute, lazyRouteComponent, getRouteApi
for typed hooks in split files, codeSplitGroupings per-route override,
splitBehavior programmatic config, critical vs non-critical properties.
-type: sub-skill
-library: tanstack-router
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-router
+ library_version: '1.171.15'
requires:
- router-core
sources:
diff --git a/packages/router-core/skills/router-core/data-loading/SKILL.md b/packages/router-core/skills/router-core/data-loading/SKILL.md
index 59a71a0cca..6a4364ff1f 100644
--- a/packages/router-core/skills/router-core/data-loading/SKILL.md
+++ b/packages/router-core/skills/router-core/data-loading/SKILL.md
@@ -1,14 +1,15 @@
---
-name: router-core/data-loading
+name: data-loading
description: >-
Route loader option, loaderDeps for cache keys, staleTime/gcTime/
defaultPreloadStaleTime SWR caching, pendingComponent/pendingMs/
pendingMinMs, errorComponent/onError/onCatch, beforeLoad, router
context and createRootRouteWithContext DI pattern, router.invalidate,
Await component, deferred data loading with unawaited promises.
-type: sub-skill
-library: tanstack-router
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-router
+ library_version: '1.171.15'
requires:
- router-core
sources:
@@ -216,13 +217,29 @@ Route-level context via `beforeLoad`:
```tsx
export const Route = createFileRoute('/posts')({
- beforeLoad: () => ({
- fetchPosts: () => fetch('/api/posts').then((r) => r.json()),
+ beforeLoad: ({ context }) => ({
+ fetchPosts: context.fetchPosts,
}),
loader: ({ context: { fetchPosts } }) => fetchPosts(),
})
```
+Keep the implementation SSR-safe when the router is used by TanStack Start. A relative `fetch('/api/posts')` works in a browser event handler, but Node and many server runtimes require an absolute URL during SSR. For app-internal data in Start, call a server function from the loader:
+
+```tsx
+import { createServerFn } from '@tanstack/react-start'
+
+const getPosts = createServerFn({ method: 'GET' }).handler(() => {
+ return db.posts.findMany()
+})
+
+export const Route = createFileRoute('/posts')({
+ loader: () => getPosts(),
+})
+```
+
+Use a server route plus an origin-derived absolute URL only when the HTTP boundary itself is required. Do not hard-code the production origin.
+
### Deferred Data Loading
Return unawaited promises from the loader for non-critical data. Use the `Await` component to render them:
@@ -276,19 +293,17 @@ function AddPostButton() {
const router = useRouter()
const handleAdd = async () => {
- await fetch('/api/posts', { method: 'POST', body: '...' })
- router.invalidate()
+ await createPost({ title: 'New post' })
+ await router.invalidate({ sync: true })
}
return
}
```
-For synchronous invalidation (wait until loaders finish):
+Use `await router.invalidate({ sync: true })` when the next step requires refreshed loader data.
-```tsx
-await router.invalidate({ sync: true })
-```
+Treat the mutation and invalidation as one workflow. The mutation must persist before invalidation starts, and the loader must read from the same authoritative store. Verify create, update, and delete through the rendered route, including a fresh reload; local component state can hide a stale loader or non-persistent write.
### Error Handling
@@ -361,16 +376,13 @@ export const Route = createFileRoute('/posts')({
},
})
-// CORRECT — loaders run in the browser, use fetch or API calls
+// CORRECT for an SPA — use a client-safe API helper
export const Route = createFileRoute('/posts')({
- loader: async () => {
- const res = await fetch('/api/posts')
- return res.json()
- },
+ loader: () => fetchPosts(),
})
```
-Do NOT put database queries, filesystem access, or server-only code in loaders unless you are using TanStack Start server functions.
+Do NOT put database queries, filesystem access, or server-only code directly in loaders. In TanStack Start, put that work in a server function and call the function from the loader. Do not use a relative `fetch('/api/...')` in an SSR loader.
### MEDIUM: Not understanding staleTime default is 0
diff --git a/packages/router-core/skills/router-core/navigation/SKILL.md b/packages/router-core/skills/router-core/navigation/SKILL.md
index 0e09ddbcec..ba1f0fd2e6 100644
--- a/packages/router-core/skills/router-core/navigation/SKILL.md
+++ b/packages/router-core/skills/router-core/navigation/SKILL.md
@@ -1,14 +1,15 @@
---
-name: router-core/navigation
+name: navigation
description: >-
Link component, useNavigate, Navigate component, router.navigate,
ToOptions/NavigateOptions/LinkOptions, from/to relative navigation,
activeOptions/activeProps, preloading (intent/viewport/render),
preloadDelay, navigation blocking (useBlocker, Block), createLink,
linkOptions helper, scroll restoration, MatchRoute.
-type: sub-skill
-library: tanstack-router
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-router
+ library_version: '1.171.15'
requires:
- router-core
sources:
diff --git a/packages/router-core/skills/router-core/not-found-and-errors/SKILL.md b/packages/router-core/skills/router-core/not-found-and-errors/SKILL.md
index b4fde048f8..2a69f16888 100644
--- a/packages/router-core/skills/router-core/not-found-and-errors/SKILL.md
+++ b/packages/router-core/skills/router-core/not-found-and-errors/SKILL.md
@@ -1,13 +1,14 @@
---
-name: router-core/not-found-and-errors
+name: not-found-and-errors
description: >-
notFound() function, notFoundComponent, defaultNotFoundComponent,
notFoundMode (fuzzy/root), errorComponent, CatchBoundary,
CatchNotFound, isNotFound, NotFoundRoute (deprecated), route
masking (mask option, createRouteMask, unmaskOnReload).
-type: sub-skill
-library: tanstack-router
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-router
+ library_version: '1.171.15'
requires:
- router-core
sources:
diff --git a/packages/router-core/skills/router-core/path-params/SKILL.md b/packages/router-core/skills/router-core/path-params/SKILL.md
index 32964d06cc..b4819f04b5 100644
--- a/packages/router-core/skills/router-core/path-params/SKILL.md
+++ b/packages/router-core/skills/router-core/path-params/SKILL.md
@@ -1,13 +1,14 @@
---
-name: router-core/path-params
+name: path-params
description: >-
Dynamic path segments ($paramName), splat routes ($ / _splat),
optional params ({-$paramName}), prefix/suffix patterns ({$param}.ext),
useParams, params.parse/stringify, pathParamsAllowedCharacters,
i18n locale patterns.
-type: sub-skill
-library: tanstack-router
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-router
+ library_version: '1.171.15'
requires:
- router-core
sources:
diff --git a/packages/router-core/skills/router-core/search-params/SKILL.md b/packages/router-core/skills/router-core/search-params/SKILL.md
index 5b509e5a50..0960297d00 100644
--- a/packages/router-core/skills/router-core/search-params/SKILL.md
+++ b/packages/router-core/skills/router-core/search-params/SKILL.md
@@ -1,13 +1,14 @@
---
-name: router-core/search-params
+name: search-params
description: >-
validateSearch, search param validation with Zod/Valibot/ArkType adapters,
fallback(), search middlewares (retainSearchParams, stripSearchParams),
custom serialization (parseSearch, stringifySearch), search param
inheritance, loaderDeps for cache keys, reading and writing search params.
-type: sub-skill
-library: tanstack-router
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-router
+ library_version: '1.171.15'
requires:
- router-core
sources:
diff --git a/packages/router-core/skills/router-core/ssr/SKILL.md b/packages/router-core/skills/router-core/ssr/SKILL.md
index de3fc9a6d7..d1e0524f13 100644
--- a/packages/router-core/skills/router-core/ssr/SKILL.md
+++ b/packages/router-core/skills/router-core/ssr/SKILL.md
@@ -1,5 +1,5 @@
---
-name: router-core/ssr
+name: ssr
description: >-
Non-streaming and streaming SSR, RouterClient/RouterServer,
renderRouterToString/renderRouterToStream, createRequestHandler,
@@ -7,9 +7,10 @@ description: >-
components, head route option (meta/links/styles/scripts),
ScriptOnce, automatic loader dehydration/hydration, memory
history on server, data serialization, document head management.
-type: sub-skill
-library: tanstack-router
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-router
+ library_version: '1.171.15'
requires:
- router-core
- router-core/data-loading
diff --git a/packages/router-core/skills/router-core/type-safety/SKILL.md b/packages/router-core/skills/router-core/type-safety/SKILL.md
index 7b7c53bfa8..ce9204677e 100644
--- a/packages/router-core/skills/router-core/type-safety/SKILL.md
+++ b/packages/router-core/skills/router-core/type-safety/SKILL.md
@@ -1,14 +1,15 @@
---
-name: router-core/type-safety
+name: type-safety
description: >-
Full type inference philosophy (never cast, never annotate inferred
values), Register module declaration, from narrowing on hooks and
Link, strict:false for shared components, getRouteApi for code-split
typed access, addChildren with object syntax for TS perf, LinkProps
and ValidateLinkOptions type utilities, as const satisfies pattern.
-type: sub-skill
-library: tanstack-router
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-router
+ library_version: '1.171.15'
requires:
- router-core
sources:
@@ -489,4 +490,10 @@ const search = Route.useSearch()
If a build error mentions `react-router-dom`, `next/`, `pages/_app`, or duplicate `/` routes, fix the import — don't paper over with type assertions.
+### 6. CRITICAL: Treating typecheck as proof of runtime schema propagation
+
+Types can say a field exists while a database projection, API serializer, or server function omits it. When adding or renaming a field, trace the value through storage, validation, handler output, loader data, and rendered UI. Do not cast the response to the desired type.
+Add a runtime assertion against the real handler or serialized response, such as `expect(await getOrder({ data: { id } })).toMatchObject({ totalCents: 2599 })`.
+Then run the route-level test and production build. The type test remains necessary, but it is not the runtime contract test.
+
See also: router-core (Register setup), router-core/navigation (from narrowing), router-core/code-splitting (getRouteApi).
diff --git a/packages/router-plugin/skills/_artifacts/domain_map.yaml b/packages/router-plugin/skills/_artifacts/domain_map.yaml
index 8ce9e31f4d..dd83f2c913 100644
--- a/packages/router-plugin/skills/_artifacts/domain_map.yaml
+++ b/packages/router-plugin/skills/_artifacts/domain_map.yaml
@@ -1,12 +1,12 @@
# domain_map.yaml
# Library: @tanstack/router-plugin
-# Version: 1.166.2
+# Version: 1.168.23
# Date: 2026-03-08
# Status: reviewed
library:
name: '@tanstack/router-plugin'
- version: '1.166.2'
+ version: '1.168.23'
repository: 'https://github.com/TanStack/router'
description: >-
Bundler plugin for route generation and automatic code splitting.
@@ -59,4 +59,12 @@ skills:
priority: MEDIUM
status: active
+ - mistake: 'Editing routeTree.gen.ts instead of regenerating'
+ mechanism: >-
+ Manual changes are overwritten and can put source routes, generated
+ types, and runtime routing out of sync. Fix source or config and
+ regenerate the tree.
+ priority: HIGH
+ status: active
+
gaps: []
diff --git a/packages/router-plugin/skills/_artifacts/skill_spec.md b/packages/router-plugin/skills/_artifacts/skill_spec.md
index 4d4881232f..586ee34ade 100644
--- a/packages/router-plugin/skills/_artifacts/skill_spec.md
+++ b/packages/router-plugin/skills/_artifacts/skill_spec.md
@@ -12,13 +12,14 @@ Bundler plugin for route generation and automatic code splitting. Supports Vite,
| Skill | Type | Domain | What it covers | Failure modes |
| ------------- | ---- | ------------------- | -------------------------------------------------------------- | ------------- |
-| router-plugin | core | bundler-integration | Vite/Webpack/Rspack/esbuild plugins, route gen, code splitting | 2 |
+| router-plugin | core | bundler-integration | Vite/Webpack/Rspack/esbuild plugins, route gen, code splitting | 3 |
## Failure Mode Inventory
-### router-plugin (2 failure modes)
+### router-plugin (3 failure modes)
-| # | Mistake | Priority | Source |
-| --- | ---------------------------------------------------- | -------- | ----------- |
-| 1 | Using wrong plugin export for bundler | HIGH | source/docs |
-| 2 | Misconfiguring routesDirectory or generatedRouteTree | MEDIUM | source/docs |
+| # | Mistake | Priority | Source |
+| --- | ---------------------------------------------------- | -------- | ----------------- |
+| 1 | Using wrong plugin export for bundler | HIGH | source/docs |
+| 2 | Misconfiguring routesDirectory or generatedRouteTree | MEDIUM | source/docs |
+| 3 | Editing routeTree.gen.ts instead of regenerating | HIGH | consistency audit |
diff --git a/packages/router-plugin/skills/_artifacts/skill_tree.yaml b/packages/router-plugin/skills/_artifacts/skill_tree.yaml
index eccd302d0f..a313cc8a4e 100644
--- a/packages/router-plugin/skills/_artifacts/skill_tree.yaml
+++ b/packages/router-plugin/skills/_artifacts/skill_tree.yaml
@@ -1,6 +1,6 @@
library:
name: '@tanstack/router-plugin'
- version: '1.166.2'
+ version: '1.168.23'
repository: 'https://github.com/TanStack/router'
description: >-
Bundler plugin for route generation and automatic code splitting.
diff --git a/packages/router-plugin/skills/router-plugin/SKILL.md b/packages/router-plugin/skills/router-plugin/SKILL.md
index b3ba5db5a3..972584dc96 100644
--- a/packages/router-plugin/skills/router-plugin/SKILL.md
+++ b/packages/router-plugin/skills/router-plugin/SKILL.md
@@ -5,9 +5,10 @@ description: >-
code splitting. Supports Vite, Webpack, Rspack, and esbuild.
Configures autoCodeSplitting, routesDirectory, target framework,
and code split groupings.
-type: core
-library: tanstack-router
-library_version: '1.166.2'
+metadata:
+ type: core
+ library: tanstack-router
+ library_version: '1.168.23'
sources:
- TanStack/router:packages/router-plugin/src
- TanStack/router:docs/router/routing/file-based-routing.md
@@ -170,6 +171,18 @@ The composed plugin assembles up to 3 sub-plugins:
2. **Code Splitter** (when `autoCodeSplitting: true`) — Splits route files into lazy-loaded chunks using virtual modules
3. **HMR** (dev mode, when code splitter is off) — Hot-reloads route changes without full refresh
+## Route Refactor Workflow
+
+When moving, renaming, adding, or deleting file routes:
+
+1. Change the source files under `routesDirectory`. Keep the exported route identifier named `Route`.
+2. Let the bundler plugin regenerate the tree, or run `pnpm exec tsr generate` when the project uses the CLI.
+3. Inspect the generated diff for the expected route IDs, parents, paths, and imports. Never repair `routeTree.gen.ts` by hand.
+4. Update links, redirects, `from` narrowing, params, preload calls, and tests that reference the old route.
+5. Run route-generation tests, type tests, and a production build. A passing editor typecheck does not prove the plugin generated or split the new route correctly.
+
+Commit `routeTree.gen.ts`; it is generated source used by the application at runtime.
+
## Individual Plugin Exports
For advanced use, each sub-plugin is exported separately from the Vite entry:
@@ -227,6 +240,10 @@ function AboutPage() {
}
```
+### 4. HIGH: Editing the generated route tree
+
+Changes to `routeTree.gen.ts` are overwritten and can leave source routes, generated types, and runtime routing out of sync. Fix route filenames or plugin configuration, regenerate, and verify the generated diff instead.
+
## Cross-References
- [router-core/code-splitting](../../../router-core/skills/router-core/code-splitting/SKILL.md) — manual code splitting concepts
diff --git a/packages/solid-router/skills/solid-router/SKILL.md b/packages/solid-router/skills/solid-router/SKILL.md
index 75c82805df..0cfd22ad73 100644
--- a/packages/solid-router/skills/solid-router/SKILL.md
+++ b/packages/solid-router/skills/solid-router/SKILL.md
@@ -8,10 +8,11 @@ description: >-
Outlet, CatchBoundary, ErrorComponent. Solid-specific patterns
with Accessor returns, createSignal/createMemo/createEffect,
Show/Switch/Match/Dynamic, and @solidjs/meta for head management.
-type: framework
-library: tanstack-router
-library_version: '1.166.2'
-framework: solid
+metadata:
+ type: framework
+ library: tanstack-router
+ library_version: '1.166.2'
+ framework: solid
requires:
- router-core
sources:
@@ -22,8 +23,6 @@ sources:
This skill builds on router-core. Read [router-core](../../../router-core/skills/router-core/SKILL.md) first for foundational concepts.
-This skill covers the Solid-specific bindings, components, hooks, and setup for TanStack Router.
-
> **CRITICAL**: TanStack Router types are FULLY INFERRED. Never cast, never annotate inferred values.
> **CRITICAL**: TanStack Router is CLIENT-FIRST. Loaders run on the client by default, not on the server.
> **CRITICAL**: Most hooks return `Accessor` — you MUST call the accessor (`value()`) to read the reactive value. This is the #1 difference from the React version.
diff --git a/packages/solid-start/skills/solid-start/SKILL.md b/packages/solid-start/skills/solid-start/SKILL.md
index 03bab29ba8..236bac2b0c 100644
--- a/packages/solid-start/skills/solid-start/SKILL.md
+++ b/packages/solid-start/skills/solid-start/SKILL.md
@@ -5,10 +5,11 @@ description: >-
Vite plugin, StartClient, StartServer, Solid-specific setup,
re-exports from @tanstack/start-client-core. Full project setup
with Solid.
-type: framework
-library: tanstack-start
-library_version: '1.166.2'
-framework: solid
+metadata:
+ type: framework
+ library: tanstack-start
+ library_version: '1.166.2'
+ framework: solid
requires:
- start-core
sources:
diff --git a/packages/start-client-core/skills/_artifacts/domain_map.yaml b/packages/start-client-core/skills/_artifacts/domain_map.yaml
index 25c34aabfe..ac17d49f56 100644
--- a/packages/start-client-core/skills/_artifacts/domain_map.yaml
+++ b/packages/start-client-core/skills/_artifacts/domain_map.yaml
@@ -1,13 +1,13 @@
# domain_map.yaml
# Generated by skill-domain-discovery
# Library: TanStack Start
-# Version: 1.166.2
+# Version: 1.170.14
# Date: 2026-03-07
# Status: reviewed
library:
name: '@tanstack/react-start'
- version: '1.166.2'
+ version: '1.170.14'
repository: 'https://github.com/TanStack/router'
description: >-
Full-stack React framework built on TanStack Router and Vite. Adds
@@ -189,6 +189,15 @@ skills:
priority: HIGH
status: active
+ - mistake: 'Not using useServerFn for component calls'
+ mechanism: >-
+ Component calls need useServerFn so redirects and not-found
+ responses use the active router instead of falling through as
+ ordinary function results.
+ source: 'docs/start/framework/react/guide/server-functions.md'
+ priority: MEDIUM
+ status: active
+
- mistake: 'Generating Next.js or Remix server patterns'
mechanism: >-
Agents generate getServerSideProps, "use server" directives,
@@ -204,6 +213,39 @@ skills:
priority: CRITICAL
status: active
+ - mistake: 'Relying on a route guard to protect a server function'
+ mechanism: >-
+ beforeLoad protects route UX, but createServerFn exposes an
+ independently callable endpoint. Private handlers must enforce
+ authentication and authorization themselves or through middleware.
+ source: 'protocol-v4 evaluation'
+ priority: CRITICAL
+ status: active
+
+ - mistake: 'Self-fetching a relative API URL from an SSR loader'
+ mechanism: >-
+ Loaders also run on the server, where relative URLs may not have a
+ base. App-internal loaders should call a server function directly.
+ source: 'protocol-v4 evaluation'
+ priority: CRITICAL
+ status: active
+
+ - mistake: 'Mutating without invalidating cached loader data'
+ mechanism: >-
+ Local state can show a write that was not persisted or leave route
+ cache stale. Await the write, invalidate, and verify a fresh reload.
+ source: 'protocol-v4 evaluation'
+ priority: HIGH
+ status: active
+
+ - mistake: 'Treating typecheck as proof of output schema propagation'
+ mechanism: >-
+ A typed model can still be projected or serialized without the new
+ field. Assert the actual handler or HTTP payload at runtime.
+ source: 'protocol-v4 evaluation'
+ priority: CRITICAL
+ status: active
+
# ── Middleware and Context ───────────────────────────────────────
- name: 'Middleware'
slug: 'middleware'
@@ -354,6 +396,23 @@ skills:
priority: CRITICAL
status: active
+ - mistake: 'Hydration mismatches from env-dependent rendering'
+ mechanism: >-
+ Rendering different output from server-only environment state
+ causes the client hydration pass to disagree with the SSR HTML.
+ Transfer stable data or defer environment-dependent UI.
+ source: 'docs/start/framework/react/guide/execution-model.md'
+ priority: HIGH
+ status: active
+
+ - mistake: 'Using a relative URL in an isomorphic loader'
+ mechanism: >-
+ Browser fetch resolves relative URLs against the document, while an
+ SSR runtime may have no base URL. Use a server function boundary.
+ source: 'protocol-v4 evaluation'
+ priority: CRITICAL
+ status: active
+
# ── Server Routes ────────────────────────────────────────────────
- name: 'Server Routes'
slug: 'server-routes'
@@ -387,6 +446,39 @@ skills:
priority: MEDIUM
status: active
+ - mistake: 'Forgetting to await request body methods'
+ mechanism: >-
+ Request body readers return promises. Using request.json(),
+ request.text(), or request.formData() without await passes a promise
+ instead of the parsed request body.
+ source: 'docs/start/framework/react/guide/server-routes.md'
+ priority: MEDIUM
+ status: active
+
+ - mistake: 'Relying on page auth to protect a server route'
+ mechanism: >-
+ API handlers are directly callable and must authenticate and
+ authorize private reads and writes at the handler boundary.
+ source: 'protocol-v4 evaluation'
+ priority: CRITICAL
+ status: active
+
+ - mistake: 'Self-fetching a server route from an SSR loader'
+ mechanism: >-
+ A relative API URL can fail during SSR. Share one server-side service
+ between a server function and server route instead.
+ source: 'protocol-v4 evaluation'
+ priority: CRITICAL
+ status: active
+
+ - mistake: 'Omitting a field from serialized response output'
+ mechanism: >-
+ Typechecking does not inspect the runtime Response payload. Test the
+ serialized output when a schema changes.
+ source: 'protocol-v4 evaluation'
+ priority: CRITICAL
+ status: active
+
# ── Deployment and Rendering ─────────────────────────────────────
- name: 'Deployment'
slug: 'deployment'
diff --git a/packages/start-client-core/skills/_artifacts/skill_spec.md b/packages/start-client-core/skills/_artifacts/skill_spec.md
index a29621e478..841105ee17 100644
--- a/packages/start-client-core/skills/_artifacts/skill_spec.md
+++ b/packages/start-client-core/skills/_artifacts/skill_spec.md
@@ -17,33 +17,38 @@ TanStack Start is a full-stack React framework built on TanStack Router and Vite
| Skill | Type | Domain | What it covers | Failure modes |
| ------------------- | --------- | ------------------------ | ------------------------------------------------------- | ------------- |
-| start-core | core | project-setup | tanstackStart(), getRouter(), root route, entries | 3 |
-| server-functions | core | server-functions | createServerFn, validation, useServerFn, streaming | 4 |
+| start-core | core | project-setup | tanstackStart(), getRouter(), root route, entries | 4 |
+| server-functions | core | server-functions | createServerFn, validation, useServerFn, streaming | 8 |
| middleware | core | middleware-and-context | createMiddleware, context, global middleware, factories | 3 |
-| execution-model | core | execution-model | Isomorphic defaults, environment functions, env vars | 4 |
-| server-routes | core | server-routes | server property, HTTP handlers, createHandlers | 2 |
+| execution-model | core | execution-model | Isomorphic defaults, environment functions, env vars | 5 |
+| server-routes | core | server-routes | server property, HTTP handlers, createHandlers | 5 |
| deployment | core | deployment-and-rendering | Hosting, SSR modes, prerendering, SEO | 3 |
| react-start | framework | project-setup | React bindings, useServerFn, full setup | 3 |
| migrate-from-nextjs | lifecycle | project-setup | Next.js App Router migration checklist | 3 |
## Failure Mode Inventory
-### start-core (3 failure modes)
+### start-core (4 failure modes)
| # | Mistake | Priority | Source |
| --- | ----------------------------------------------- | -------- | ----------------------- |
| 1 | React plugin before Start plugin in Vite config | CRITICAL | docs/build-from-scratch |
| 2 | Enabling verbatimModuleSyntax in tsconfig | HIGH | docs/build-from-scratch |
| 3 | Missing Scripts component in root route | HIGH | docs/guide/routing |
+| 4 | Loading every overlapping Start skill | HIGH | protocol-v4 evaluation |
-### server-functions (4 failure modes)
+### server-functions (8 failure modes)
-| # | Mistake | Priority | Source |
-| --- | --------------------------------------------------------------------------- | -------- | --------------------------- |
-| 1 | Putting server-only code in loaders instead of server functions | CRITICAL | maintainer interview |
-| 2 | Generating Next.js/Remix server patterns ("use server", getServerSideProps) | CRITICAL | maintainer interview |
-| 3 | Using dynamic imports for server functions | HIGH | docs/guide/server-functions |
-| 4 | Not using useServerFn for component calls | MEDIUM | docs/guide/server-functions |
+| # | Mistake | Priority | Source |
+| --- | --------------------------------------------------------------- | -------- | --------------------------- |
+| 1 | Putting server-only code in loaders instead of server functions | CRITICAL | maintainer interview |
+| 2 | Using dynamic imports for server functions | HIGH | docs/guide/server-functions |
+| 3 | Not using useServerFn for component calls | MEDIUM | docs/guide/server-functions |
+| 4 | Generating Next.js or Remix server patterns | CRITICAL | maintainer interview |
+| 5 | Relying on a route guard to protect a server function | CRITICAL | protocol-v4 evaluation |
+| 6 | Self-fetching a relative API URL from an SSR loader | CRITICAL | protocol-v4 evaluation |
+| 7 | Mutating without invalidating cached loader data | HIGH | protocol-v4 evaluation |
+| 8 | Treating typecheck as proof of output schema propagation | CRITICAL | protocol-v4 evaluation |
### middleware (3 failure modes)
@@ -53,7 +58,7 @@ TanStack Start is a full-stack React framework built on TanStack Router and Vite
| 2 | Confusing request vs server function middleware | MEDIUM | docs/guide/middleware |
| 3 | Wrong middleware method order | MEDIUM | docs/guide/middleware |
-### execution-model (4 failure modes)
+### execution-model (5 failure modes)
| # | Mistake | Priority | Source |
| --- | ------------------------------------------------- | -------- | -------------------------------- |
@@ -61,13 +66,17 @@ TanStack Start is a full-stack React framework built on TanStack Router and Vite
| 2 | Exposing secrets via module-level process.env | CRITICAL | docs/guide/execution-model |
| 3 | Using VITE\_ prefix for server secrets | CRITICAL | docs/guide/environment-variables |
| 4 | Hydration mismatches from env-dependent rendering | HIGH | docs/guide/execution-model |
+| 5 | Using a relative URL in an isomorphic loader | CRITICAL | protocol-v4 evaluation |
-### server-routes (2 failure modes)
+### server-routes (5 failure modes)
-| # | Mistake | Priority | Source |
-| --- | ---------------------------------------- | -------- | ------------------------ |
-| 1 | Duplicate route path resolution | MEDIUM | docs/guide/server-routes |
-| 2 | Forgetting to await request body methods | MEDIUM | docs/guide/server-routes |
+| # | Mistake | Priority | Source |
+| --- | ------------------------------------------------ | -------- | ------------------------ |
+| 1 | Duplicate path resolution for server routes | MEDIUM | docs/guide/server-routes |
+| 2 | Forgetting to await request body methods | MEDIUM | docs/guide/server-routes |
+| 3 | Relying on page auth to protect a server route | CRITICAL | protocol-v4 evaluation |
+| 4 | Self-fetching a server route from an SSR loader | CRITICAL | protocol-v4 evaluation |
+| 5 | Omitting a field from serialized response output | CRITICAL | protocol-v4 evaluation |
### deployment (3 failure modes)
diff --git a/packages/start-client-core/skills/_artifacts/skill_tree.yaml b/packages/start-client-core/skills/_artifacts/skill_tree.yaml
index 3ab8793408..673f7ab543 100644
--- a/packages/start-client-core/skills/_artifacts/skill_tree.yaml
+++ b/packages/start-client-core/skills/_artifacts/skill_tree.yaml
@@ -1,7 +1,7 @@
# packages/start-client-core/skills/_artifacts/skill_tree.yaml
library:
name: '@tanstack/start-client-core'
- version: '1.166.2'
+ version: '1.170.14'
repository: 'https://github.com/TanStack/router'
description: >-
Framework-agnostic client-side core for TanStack Start.
diff --git a/packages/start-client-core/skills/start-core/SKILL.md b/packages/start-client-core/skills/start-core/SKILL.md
index 82481417bc..60d9f3fcd1 100644
--- a/packages/start-client-core/skills/start-core/SKILL.md
+++ b/packages/start-client-core/skills/start-core/SKILL.md
@@ -5,9 +5,10 @@ description: >-
getRouter() factory, root route document shell (HeadContent,
Scripts, Outlet), client/server entry points, routeTree.gen.ts,
tsconfig configuration. Entry point for all Start skills.
-type: core
-library: tanstack-start
-library_version: '1.166.2'
+metadata:
+ type: core
+ library: tanstack-start
+ library_version: '1.170.14'
sources:
- TanStack/router:docs/start/framework/react/build-from-scratch.md
- TanStack/router:docs/start/framework/react/quick-start.md
@@ -22,6 +23,8 @@ TanStack Start is a full-stack React framework built on TanStack Router and Vite
> **CRITICAL**: TanStack Start is NOT Next.js. Do not generate `getServerSideProps`, `"use server"` directives, `app/layout.tsx`, or any Next.js/Remix patterns. Use `createServerFn` for server-only code.
> **CRITICAL**: Types are FULLY INFERRED. Never cast, never annotate inferred values.
+Use this entry skill to pick one primary workflow. Do not load every Start sub-skill. Add another only when the implementation crosses that boundary; for example, a protected mutation needs `server-functions` plus `auth-server-primitives`, while a public REST endpoint needs `server-routes` alone.
+
## Sub-Skills
| Task | Sub-Skill |
@@ -55,6 +58,20 @@ Need to deploy, configure SSR, or prerender?
→ start-core/deployment
```
+## Full-Stack Delivery Workflow
+
+For application data loaded by a Start route:
+
+1. Put database, filesystem, secrets, and persistence code behind `createServerFn`.
+2. Call the server function directly from the route loader. Do not self-fetch a relative `/api/...` URL from an SSR loader.
+3. Validate every input and enforce auth in the server function or middleware. `beforeLoad` only protects route UX.
+4. After a mutation resolves, invalidate the router or the external query cache and await the refresh when the UI must be current before continuing.
+5. For schema changes, update storage, validation, handler serialization, loader, and UI. Assert the actual runtime payload; typechecking alone cannot detect an omitted serialized field.
+
+Use a server route when the raw HTTP contract is the product: webhooks, third-party clients, feeds, file responses, or a public REST API. When the Start UI and a server route share data, call one server-side service from both instead of making the SSR loader fetch its own API route.
+
+Before finishing, test the initial SSR request, client navigation, mutation followed by refresh, and a direct anonymous request to every protected endpoint.
+
## Project Setup
### 1. Install Dependencies
@@ -211,4 +228,4 @@ function RootComponent() {
## Version Note
-This skill targets `@tanstack/react-start` v1.166.2 and `@tanstack/start-client-core` v1.166.2.
+This skill targets `@tanstack/start-client-core` v1.170.14.
diff --git a/packages/start-client-core/skills/start-core/auth-server-primitives/SKILL.md b/packages/start-client-core/skills/start-core/auth-server-primitives/SKILL.md
index 40205bc074..8f20dcaa27 100644
--- a/packages/start-client-core/skills/start-core/auth-server-primitives/SKILL.md
+++ b/packages/start-client-core/skills/start-core/auth-server-primitives/SKILL.md
@@ -1,5 +1,5 @@
---
-name: start-core/auth-server-primitives
+name: auth-server-primitives
description: >-
Server-side authentication primitives for TanStack Start: session
cookies (HttpOnly, Secure, SameSite, __Host- prefix), session
@@ -8,9 +8,10 @@ description: >-
enumeration defense, CSRF for non-GET RPCs, rate limiting auth
endpoints, session rotation on privilege change. Pairs with
router-core/auth-and-guards for the routing side.
-type: sub-skill
-library: tanstack-start
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-start
+ library_version: '1.170.14'
requires:
- start-core
- start-core/server-functions
@@ -38,6 +39,7 @@ This skill covers the **server half** of authentication: session storage, cookie
- Use CSRF or same-origin protections for non-GET server functions and server routes.
- Log authentication events and monitor failures.
- Test direct unauthenticated calls to protected server functions; they should reject before returning data.
+- Follow the anonymous redirect and inspect its HTML and serialized state. Login and unauthorized pages must not name the protected user, tenant, or record.
## Session Cookies
diff --git a/packages/start-client-core/skills/start-core/deployment/SKILL.md b/packages/start-client-core/skills/start-core/deployment/SKILL.md
index 62111f9edd..39939ea5e7 100644
--- a/packages/start-client-core/skills/start-core/deployment/SKILL.md
+++ b/packages/start-client-core/skills/start-core/deployment/SKILL.md
@@ -1,13 +1,14 @@
---
-name: start-core/deployment
+name: deployment
description: >-
Deploy to Cloudflare Workers, Netlify, Vercel, Node.js/Docker,
Bun, Railway. Selective SSR (ssr option per route), SPA mode,
static prerendering, ISR with Cache-Control headers, SEO and
head management.
-type: sub-skill
-library: tanstack-start
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-start
+ library_version: '1.170.14'
requires:
- start-core
sources:
diff --git a/packages/start-client-core/skills/start-core/execution-model/SKILL.md b/packages/start-client-core/skills/start-core/execution-model/SKILL.md
index ffed9211dc..271efe6bf1 100644
--- a/packages/start-client-core/skills/start-core/execution-model/SKILL.md
+++ b/packages/start-client-core/skills/start-core/execution-model/SKILL.md
@@ -1,14 +1,15 @@
---
-name: start-core/execution-model
+name: execution-model
description: >-
Isomorphic-by-default principle, environment boundary functions
(createServerFn, createServerOnlyFn, createClientOnlyFn,
createIsomorphicFn), ClientOnly component, useHydrated hook,
import protection, dead code elimination, environment variable
safety (VITE_ prefix, process.env).
-type: sub-skill
-library: tanstack-start
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-start
+ library_version: '1.170.14'
requires:
- start-core
sources:
@@ -24,6 +25,7 @@ Understanding where code runs is fundamental to TanStack Start. This skill cover
> **CRITICAL**: ALL code in TanStack Start is isomorphic by default — it runs in BOTH server and client bundles. Route loaders run on BOTH server (during SSR) AND client (during navigation). Server-only operations MUST use `createServerFn`.
> **CRITICAL**: Module-level `process.env` access is wrong on **two** axes — security (values leak into the client bundle) AND runtime correctness (on Cloudflare Workers and other edge runtimes, env is injected per-request, so module-level reads evaluate to `undefined` even on the server). Read env inside `.handler()` or another per-request function, never at module scope.
> **CRITICAL**: `VITE_` prefixed environment variables are exposed to the client bundle. Server secrets must NOT have the `VITE_` prefix.
+> **CRITICAL**: Relative URLs belong to browser-only code. An isomorphic loader also runs during SSR, where `fetch('/api/...')` may have no base URL. Call a server function from the loader, or keep the fetch inside an explicit environment boundary.
## Execution Control APIs
diff --git a/packages/start-client-core/skills/start-core/middleware/SKILL.md b/packages/start-client-core/skills/start-core/middleware/SKILL.md
index 483c6b89ae..972ed474af 100644
--- a/packages/start-client-core/skills/start-core/middleware/SKILL.md
+++ b/packages/start-client-core/skills/start-core/middleware/SKILL.md
@@ -1,14 +1,15 @@
---
-name: start-core/middleware
+name: middleware
description: >-
createMiddleware, request middleware (.server only), server function
middleware (.client + .server), context passing via next({ context }),
sendContext for client-server transfer, global middleware via
createStart in src/start.ts, middleware factories, method order
enforcement, fetch override precedence.
-type: sub-skill
-library: tanstack-start
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-start
+ library_version: '1.170.14'
requires:
- start-core
- start-core/server-functions
diff --git a/packages/start-client-core/skills/start-core/server-functions/SKILL.md b/packages/start-client-core/skills/start-core/server-functions/SKILL.md
index 3bafbad624..603cbfa2be 100644
--- a/packages/start-client-core/skills/start-core/server-functions/SKILL.md
+++ b/packages/start-client-core/skills/start-core/server-functions/SKILL.md
@@ -1,14 +1,15 @@
---
-name: start-core/server-functions
+name: server-functions
description: >-
createServerFn (GET/POST), validator (Zod or function),
useServerFn hook, server context utilities (getRequest,
getRequestHeader, setResponseHeader, setResponseStatus), error
handling (throw errors, redirect, notFound), streaming, FormData
handling, file organization (.functions.ts, .server.ts).
-type: sub-skill
-library: tanstack-start
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-start
+ library_version: '1.170.14'
requires:
- start-core
sources:
@@ -92,6 +93,52 @@ function DeleteButton({ postId }: { postId: string }) {
}
```
+## Cache-Coherent Mutations
+
+Keep reads and writes behind server functions that use the same authoritative store. Await the write, then invalidate the route cache so its loader reads the persisted result:
+
+```tsx
+const listIssues = createServerFn({ method: 'GET' }).handler(() => {
+ return db.issues.findMany()
+})
+
+const createIssue = createServerFn({ method: 'POST' })
+ .validator((data: unknown) => {
+ if (
+ typeof data !== 'object' ||
+ data === null ||
+ !('title' in data) ||
+ typeof data.title !== 'string' ||
+ data.title.trim().length === 0
+ ) {
+ throw new Error('Title is required')
+ }
+ return { title: data.title.trim() }
+ })
+ .handler(async ({ data }) => {
+ return db.issues.create({ data })
+ })
+
+export const Route = createFileRoute('/issues')({
+ loader: () => listIssues(),
+ component: IssuesPage,
+})
+
+function IssuesPage() {
+ const router = useRouter()
+ const createIssueFn = useServerFn(createIssue)
+
+ const handleCreate = async (title: string) => {
+ await createIssueFn({ data: { title } })
+ await router.invalidate({ sync: true })
+ }
+
+ // render Route.useLoaderData() and call handleCreate from the form
+}
+```
+
+Do not update only local component state after a persistent mutation. Verify the rendered list after create, update, delete, and a fresh page load.
+
## Input Validation
### Basic Validator
@@ -123,6 +170,8 @@ const createUser = createServerFn({ method: 'POST' })
})
```
+Input validation does not validate output serialization. When a response schema changes, update the database selection, service return value, server-function result, loader consumer, and UI. Add a runtime test that calls the handler or HTTP boundary and asserts the new field in the returned payload.
+
### FormData
```tsx
@@ -425,6 +474,22 @@ const signupFn = useServerFn(signup) // signup throws redirect on success
If in doubt: wrap with `useServerFn`. It's a no-op for plain-data functions and the safe default when a function might later add a redirect.
+### 8. CRITICAL: Self-fetching a relative API URL from a loader
+
+```tsx
+// WRONG — this loader also runs during SSR, where a relative URL may fail
+export const Route = createFileRoute('/issues')({
+ loader: () => fetch('/api/issues').then((response) => response.json()),
+})
+
+// CORRECT — call the server function; the client build gets an RPC stub
+export const Route = createFileRoute('/issues')({
+ loader: () => listIssues(),
+})
+```
+
+Relative `fetch` is fine in a browser-only event handler. It is not a universal loader data strategy.
+
## Cross-References
- [start-core/execution-model](../execution-model/SKILL.md) — understanding where code runs
diff --git a/packages/start-client-core/skills/start-core/server-routes/SKILL.md b/packages/start-client-core/skills/start-core/server-routes/SKILL.md
index 101541b2aa..9655f243ed 100644
--- a/packages/start-client-core/skills/start-core/server-routes/SKILL.md
+++ b/packages/start-client-core/skills/start-core/server-routes/SKILL.md
@@ -1,14 +1,15 @@
---
-name: start-core/server-routes
+name: server-routes
description: >-
Server-side API endpoints using the server property on
createFileRoute, HTTP method handlers (GET, POST, PUT, DELETE),
createHandlers for per-handler middleware, handler context
(request, params, context), request body parsing, response
helpers, file naming for API routes.
-type: sub-skill
-library: tanstack-start
-library_version: '1.166.2'
+metadata:
+ type: sub-skill
+ library: tanstack-start
+ library_version: '1.170.14'
requires:
- start-core
sources:
@@ -19,6 +20,8 @@ sources:
Server routes are API endpoints defined alongside app routes in the `src/routes` directory. They use the `server` property on `createFileRoute` and handle raw HTTP requests.
+Use server routes when callers need an HTTP contract. For data used only by the Start application, prefer a server function and call it directly from the loader. A route loader runs during SSR and client navigation, so `fetch('/api/...')` is not a portable loader pattern.
+
## Basic Server Route
```ts
@@ -77,6 +80,39 @@ function HelloComponent() {
}
```
+The relative `fetch('/hello')` above is safe because it runs only in a browser click handler.
+
+## Sharing Data with a Start Route
+
+Do not make the SSR loader call its own server route. Put the business operation in a server-only service, then expose it through both boundaries when both are required:
+
+```tsx
+// src/server/issues.server.ts
+export function listIssues() {
+ return db.issues.findMany()
+}
+
+// src/routes/api/issues.ts
+export const Route = createFileRoute('/api/issues')({
+ server: {
+ handlers: {
+ GET: async () => Response.json(await listIssues()),
+ },
+ },
+})
+
+// src/routes/issues.tsx
+const getIssues = createServerFn({ method: 'GET' }).handler(() => {
+ return listIssues()
+})
+
+export const Route = createFileRoute('/issues')({
+ loader: () => getIssues(),
+})
+```
+
+This keeps SSR independent of URL resolution and keeps one source of business logic.
+
## File Route Conventions
Server routes follow TanStack Router file-based routing conventions:
@@ -253,7 +289,11 @@ export const Route = createFileRoute('/api/posts')({
## Common Mistakes
-### 1. MEDIUM: Duplicate route paths
+### 1. CRITICAL: Protecting the page but not the server route
+
+Every handler that reads or writes private data must authenticate and authorize the request through route middleware, handler middleware, or an in-handler check. A router `beforeLoad` redirect does not protect `/api/...`. Test the handler directly without cookies and assert that no private payload is returned.
+
+### 2. MEDIUM: Duplicate route paths
```text
# WRONG — both resolve to /users, causes error
@@ -264,7 +304,7 @@ routes/users/index.ts
routes/users.ts
```
-### 2. MEDIUM: Forgetting to await request body methods
+### 3. MEDIUM: Forgetting to await request body methods
```ts
// WRONG — body is a Promise, not the actual data
@@ -274,6 +314,10 @@ const body = request.json()
const body = await request.json()
```
+### 4. HIGH: Trusting TypeScript as response-schema validation
+
+Validate request input and test the serialized `Response` output. A typed service can still be projected or serialized without a newly added field. For schema changes, assert `await response.json()` at the server-route boundary.
+
## Cross-References
- [start-core/middleware](../middleware/SKILL.md) — middleware for server routes
diff --git a/packages/start-server-core/skills/_artifacts/domain_map.yaml b/packages/start-server-core/skills/_artifacts/domain_map.yaml
index 1a6351bdea..7dc4d303ac 100644
--- a/packages/start-server-core/skills/_artifacts/domain_map.yaml
+++ b/packages/start-server-core/skills/_artifacts/domain_map.yaml
@@ -1,12 +1,12 @@
# domain_map.yaml
# Library: @tanstack/start-server-core
-# Version: 1.166.2
+# Version: 1.169.17
# Date: 2026-03-08
# Status: reviewed
library:
name: '@tanstack/start-server-core'
- version: '1.166.2'
+ version: '1.169.17'
repository: 'https://github.com/TanStack/router'
description: >-
Server-side runtime for TanStack Start: createStartHandler,
@@ -62,4 +62,20 @@ skills:
priority: MEDIUM
status: active
+ - mistake: 'Capturing request or environment state at module scope'
+ mechanism: >-
+ Request context and edge runtime environment values are per-request.
+ Module-level capture can read undefined values or leak state between
+ concurrent requests.
+ priority: CRITICAL
+ status: active
+
+ - mistake: 'Treating cookie session data as authoritative persistence'
+ mechanism: >-
+ Cookie sessions should contain a small stable identifier. Current
+ permissions and revocable state belong in an authoritative server
+ store and must be loaded for each protected request.
+ priority: HIGH
+ status: active
+
gaps: []
diff --git a/packages/start-server-core/skills/_artifacts/skill_spec.md b/packages/start-server-core/skills/_artifacts/skill_spec.md
index 19270dc59a..402eb2c118 100644
--- a/packages/start-server-core/skills/_artifacts/skill_spec.md
+++ b/packages/start-server-core/skills/_artifacts/skill_spec.md
@@ -12,13 +12,15 @@ Server-side runtime for TanStack Start: createStartHandler, request/response uti
| Skill | Type | Domain | What it covers | Failure modes |
| ----------------- | ---- | -------------- | ---------------------------------------------------------------- | ------------- |
-| start-server-core | core | server-runtime | createStartHandler, cookies, sessions, three-phase handling, ALS | 2 |
+| start-server-core | core | server-runtime | createStartHandler, cookies, sessions, three-phase handling, ALS | 4 |
## Failure Mode Inventory
-### start-server-core (2 failure modes)
+### start-server-core (4 failure modes)
-| # | Mistake | Priority | Source |
-| --- | ---------------------------------------------- | -------- | ----------- |
-| 1 | Missing AsyncLocalStorage setup | HIGH | source/docs |
-| 2 | Incorrect handler export for deployment target | MEDIUM | source/docs |
+| # | Mistake | Priority | Source |
+| --- | --------------------------------------------------------- | -------- | ---------------------- |
+| 1 | Missing AsyncLocalStorage setup | HIGH | source/docs |
+| 2 | Incorrect handler export for deployment target | MEDIUM | source/docs |
+| 3 | Capturing request or environment state at module scope | CRITICAL | protocol-v4 evaluation |
+| 4 | Treating cookie session data as authoritative persistence | HIGH | protocol-v4 evaluation |
diff --git a/packages/start-server-core/skills/_artifacts/skill_tree.yaml b/packages/start-server-core/skills/_artifacts/skill_tree.yaml
index 6c792cf1bd..70125a39b6 100644
--- a/packages/start-server-core/skills/_artifacts/skill_tree.yaml
+++ b/packages/start-server-core/skills/_artifacts/skill_tree.yaml
@@ -1,6 +1,6 @@
library:
name: '@tanstack/start-server-core'
- version: '1.166.2'
+ version: '1.169.17'
repository: 'https://github.com/TanStack/router'
description: >-
Server-side runtime for TanStack Start: createStartHandler,
diff --git a/packages/start-server-core/skills/start-server-core/SKILL.md b/packages/start-server-core/skills/start-server-core/SKILL.md
index 7dc16d517f..95fb028cea 100644
--- a/packages/start-server-core/skills/start-server-core/SKILL.md
+++ b/packages/start-server-core/skills/start-server-core/SKILL.md
@@ -5,9 +5,10 @@ description: >-
request/response utilities (getRequest, setResponseHeader,
setCookie, getCookie, useSession), three-phase request handling,
AsyncLocalStorage context.
-type: core
-library: tanstack-start
-library_version: '1.166.2'
+metadata:
+ type: core
+ library: tanstack-start
+ library_version: '1.169.17'
sources:
- TanStack/router:packages/start-server-core/src
- TanStack/router:docs/start/framework/react/guide/server-entry-point.md
@@ -20,6 +21,8 @@ Server-side runtime for TanStack Start. Provides the request handler, request/re
> **CRITICAL**: These utilities are SERVER-ONLY. Import them from `@tanstack/-start/server`, not from the main entry point. They throw if called outside a server request context.
>
> **CRITICAL**: Types are FULLY INFERRED. Never cast, never annotate inferred values.
+>
+> **CRITICAL**: Read cookies, headers, request URLs, and runtime environment values inside the active request. Do not capture them at module scope; edge runtimes may inject them per request, and concurrent requests must never share request-derived state.
## `createStartHandler`
@@ -120,7 +123,8 @@ const serverFn = createServerFn({ method: 'POST' }).handler(async () => {
setCookie('preference', 'dark', {
httpOnly: true,
- secure: true,
+ secure: process.env.NODE_ENV === 'production',
+ sameSite: 'lax',
maxAge: 60 * 60 * 24 * 30, // 30 days
path: '/',
})
@@ -143,29 +147,84 @@ import {
clearSession,
} from '@tanstack/react-start/server'
-const sessionConfig = {
- password: process.env.SESSION_SECRET!,
- name: 'my-app-session',
- maxAge: 60 * 60 * 24 * 7, // 7 days
+type SessionData = {
+ userId?: string
+}
+
+function getSessionConfig() {
+ const password = process.env.SESSION_SECRET
+ if (!password || password.length < 32) {
+ throw new Error('SESSION_SECRET must be at least 32 characters')
+ }
+
+ return {
+ password,
+ name: 'my-app-session',
+ maxAge: 60 * 60 * 24 * 7,
+ cookie: {
+ httpOnly: true,
+ secure: process.env.NODE_ENV === 'production',
+ sameSite: 'lax' as const,
+ path: '/',
+ },
+ }
+}
+
+function getDummyPasswordHash() {
+ // Precompute this with the same algorithm and cost as real password hashes.
+ const hash = process.env.DUMMY_PASSWORD_HASH
+ if (!hash) {
+ throw new Error('DUMMY_PASSWORD_HASH is required')
+ }
+ return hash
}
// Full session manager
const getUser = createServerFn({ method: 'GET' }).handler(async () => {
- const session = await useSession<{ userId: string }>(sessionConfig)
- return session.data
+ const session = await useSession(getSessionConfig())
+ if (!session.data.userId) {
+ return null
+ }
+ return db.users.findById(session.data.userId)
})
// Update session
const login = createServerFn({ method: 'POST' })
- .validator((data: { userId: string }) => data)
+ .validator((data: unknown) => {
+ if (
+ typeof data !== 'object' ||
+ data === null ||
+ !('email' in data) ||
+ typeof data.email !== 'string' ||
+ data.email.trim().length === 0 ||
+ !('password' in data) ||
+ typeof data.password !== 'string' ||
+ data.password.length === 0
+ ) {
+ throw new Error('Invalid credentials')
+ }
+ return {
+ email: data.email.trim().toLowerCase(),
+ password: data.password,
+ }
+ })
.handler(async ({ data }) => {
- await updateSession(sessionConfig, { userId: data.userId })
+ const user = await db.users.findByEmail(data.email)
+ const passwordHash = user?.passwordHash ?? getDummyPasswordHash()
+ const passwordMatches = await verifyPassword(data.password, passwordHash)
+ if (!user || !passwordMatches) {
+ throw new Error('Invalid credentials')
+ }
+
+ await updateSession(getSessionConfig(), {
+ userId: user.id,
+ })
return { success: true }
})
// Clear session
const logout = createServerFn({ method: 'POST' }).handler(async () => {
- await clearSession(sessionConfig)
+ await clearSession(getSessionConfig())
return { success: true }
})
```
@@ -190,6 +249,14 @@ await session.update({ userId: '123' }) // Persist session data
await session.clear() // Clear session data
```
+### Production Session Rules
+
+- Keep cookie session data small and non-sensitive. Store a stable session or user ID, then load current permissions and account state from the authoritative store on each protected request.
+- Use a server-side session record when you need revocation, device tracking, large data, or immediate role changes. Put only its opaque ID in the cookie.
+- Rotate the session after login, privilege changes, password changes, and logout.
+- Use `HttpOnly`, `SameSite`, `Path=/`, and `Secure` in production. Use a `__Host-` cookie name in production only when `Secure`, no `Domain`, and `Path=/` are all enforced.
+- Use the same cookie name and path when clearing a session. Test login, authenticated refresh, expiry, logout, and a replay of the old cookie.
+
## Query Validation
Validate query string parameters using a Standard Schema:
@@ -255,6 +322,10 @@ const getAuth = createServerFn({ method: 'GET' }).handler(async () => {
Session cookies should use `secure: true` in production. The default cookie options may not enforce this.
+### 4. CRITICAL: Capturing request or environment state at module scope
+
+Do not create session config from `process.env` at module load or cache `getRequest()`, headers, cookies, or session data in a module variable. Create config and read request state inside the handler or middleware callback. This is required for per-request edge environments and prevents cross-request data leaks.
+
## Cross-References
- [start-core/server-functions](../../../start-client-core/skills/start-core/server-functions/SKILL.md) — creating server functions that use these utilities
diff --git a/packages/start-server-core/vite.config.ts b/packages/start-server-core/vite.config.ts
index aaece761fb..dd252ddb08 100644
--- a/packages/start-server-core/vite.config.ts
+++ b/packages/start-server-core/vite.config.ts
@@ -24,6 +24,12 @@ const fakeRouterEntry = fileURLToPath(
const fakeStartManifest = fileURLToPath(
new URL('./tests/fixtures/start-manifest.ts', import.meta.url),
)
+const fakePluginAdapters = fileURLToPath(
+ new URL('./src/empty-plugin-adapters.ts', import.meta.url),
+)
+const fakeServerFnResolver = fileURLToPath(
+ new URL('./src/fake-start-server-fn-resolver.ts', import.meta.url),
+)
export default mergeConfig(
config,
@@ -53,6 +59,8 @@ export default mergeConfig(
alias: {
'#tanstack-start-entry': fakeStartEntry,
'#tanstack-router-entry': fakeRouterEntry,
+ '#tanstack-start-plugin-adapters': fakePluginAdapters,
+ '#tanstack-start-server-fn-resolver': fakeServerFnResolver,
'tanstack-start-manifest:v': fakeStartManifest,
},
},
diff --git a/packages/virtual-file-routes/skills/_artifacts/domain_map.yaml b/packages/virtual-file-routes/skills/_artifacts/domain_map.yaml
index db82f87ec0..0841238c5e 100644
--- a/packages/virtual-file-routes/skills/_artifacts/domain_map.yaml
+++ b/packages/virtual-file-routes/skills/_artifacts/domain_map.yaml
@@ -1,12 +1,12 @@
# domain_map.yaml
# Library: @tanstack/virtual-file-routes
-# Version: 1.161.4
+# Version: 1.162.0
# Date: 2026-03-08
# Status: reviewed
library:
name: '@tanstack/virtual-file-routes'
- version: '1.161.4'
+ version: '1.162.0'
repository: 'https://github.com/TanStack/router'
description: >-
Programmatic route tree building as an alternative to filesystem
@@ -63,4 +63,11 @@ skills:
priority: MEDIUM
status: active
+ - mistake: 'Creating duplicate effective paths or physical mounts'
+ mechanism: >-
+ Virtual nodes and mounted physical subtrees can resolve to the same
+ path or ID. Regenerate and inspect the full tree after every refactor.
+ priority: HIGH
+ status: active
+
gaps: []
diff --git a/packages/virtual-file-routes/skills/_artifacts/skill_spec.md b/packages/virtual-file-routes/skills/_artifacts/skill_spec.md
index 834294f8f6..02f2942727 100644
--- a/packages/virtual-file-routes/skills/_artifacts/skill_spec.md
+++ b/packages/virtual-file-routes/skills/_artifacts/skill_spec.md
@@ -12,13 +12,14 @@ Programmatic route tree building as an alternative to filesystem conventions. Pr
| Skill | Type | Domain | What it covers | Failure modes |
| ------------------- | ---- | -------------------- | ---------------------------------------------------------- | ------------- |
-| virtual-file-routes | core | virtual-route-config | rootRoute, index, route, layout, physical, subtree configs | 2 |
+| virtual-file-routes | core | virtual-route-config | rootRoute, index, route, layout, physical, subtree configs | 3 |
## Failure Mode Inventory
-### virtual-file-routes (2 failure modes)
+### virtual-file-routes (3 failure modes)
-| # | Mistake | Priority | Source |
-| --- | --------------------------------------- | -------- | ----------- |
-| 1 | Forgetting rootRoute wrapper | HIGH | source/docs |
-| 2 | Using physical() path outside routesDir | MEDIUM | source/docs |
+| # | Mistake | Priority | Source |
+| --- | -------------------------------------------- | -------- | ----------------- |
+| 1 | Forgetting rootRoute wrapper | HIGH | source/docs |
+| 2 | Using physical() path outside routesDir | MEDIUM | source/docs |
+| 3 | Creating duplicate effective paths or mounts | HIGH | consistency audit |
diff --git a/packages/virtual-file-routes/skills/_artifacts/skill_tree.yaml b/packages/virtual-file-routes/skills/_artifacts/skill_tree.yaml
index f615e46c8f..7d8b510ca9 100644
--- a/packages/virtual-file-routes/skills/_artifacts/skill_tree.yaml
+++ b/packages/virtual-file-routes/skills/_artifacts/skill_tree.yaml
@@ -1,6 +1,6 @@
library:
name: '@tanstack/virtual-file-routes'
- version: '1.161.4'
+ version: '1.162.0'
repository: 'https://github.com/TanStack/router'
description: >-
Programmatic route tree building as an alternative to filesystem
diff --git a/packages/virtual-file-routes/skills/virtual-file-routes/SKILL.md b/packages/virtual-file-routes/skills/virtual-file-routes/SKILL.md
index 093d73c0ba..8e2c497fa2 100644
--- a/packages/virtual-file-routes/skills/virtual-file-routes/SKILL.md
+++ b/packages/virtual-file-routes/skills/virtual-file-routes/SKILL.md
@@ -5,9 +5,10 @@ description: >-
conventions: rootRoute, index, route, layout, physical,
defineVirtualSubtreeConfig. Use with TanStack Router plugin's
virtualRouteConfig option.
-type: core
-library: tanstack-router
-library_version: '1.161.4'
+metadata:
+ type: core
+ library: tanstack-router
+ library_version: '1.162.0'
sources:
- TanStack/router:packages/virtual-file-routes/src
- TanStack/router:docs/router/routing/virtual-file-routes.md
@@ -17,6 +18,8 @@ sources:
Build route trees programmatically instead of relying on filesystem conventions. Useful when you want explicit control over route structure, need to mix virtual and physical routes, or want to define route subtrees within file-based routing directories.
+Use this skill only when the project config contains `virtualRouteConfig`, a virtual route config file, or `__virtual.ts`. Ordinary file-route changes belong to Router Core and the Router Plugin.
+
> **CRITICAL**: Types are FULLY INFERRED. Never cast, never annotate inferred values.
## Install
@@ -216,3 +219,13 @@ layout('dashboardLayout.tsx', [route('/dashboard', 'dashboard.tsx')])
// The URL is /dashboard, and dashboardLayout.tsx wraps it
```
+
+## Refactor Audit
+
+After changing a virtual tree:
+
+1. Confirm there is exactly one `rootRoute` and that every referenced file exists relative to `routesDirectory`.
+2. Check each `route`, `layout`, and `physical` node for duplicate effective paths or IDs.
+3. Confirm each `physical()` directory is mounted once at the intended path prefix and does not overlap a virtual child.
+4. Regenerate `routeTree.gen.ts` and inspect parentage, full paths, and imports. Do not edit generated output.
+5. Update links, redirects, params, and `from` narrowing, then run generator tests, type tests, and a production build.
diff --git a/packages/vue-router/skills/vue-router/SKILL.md b/packages/vue-router/skills/vue-router/SKILL.md
index 17108957aa..5fea4fef7a 100644
--- a/packages/vue-router/skills/vue-router/SKILL.md
+++ b/packages/vue-router/skills/vue-router/SKILL.md
@@ -8,10 +8,11 @@ description: >-
Outlet, CatchBoundary, ErrorComponent, Html, Body.
Vue-specific patterns with Ref returns, defineComponent,
h() render functions, provide/inject, and computed refs.
-type: framework
-library: tanstack-router
-library_version: '1.166.2'
-framework: vue
+metadata:
+ type: framework
+ library: tanstack-router
+ library_version: '1.166.2'
+ framework: vue
requires:
- router-core
sources:
diff --git a/packages/vue-start/skills/vue-start/SKILL.md b/packages/vue-start/skills/vue-start/SKILL.md
index 13fac52d1b..fde7f32ace 100644
--- a/packages/vue-start/skills/vue-start/SKILL.md
+++ b/packages/vue-start/skills/vue-start/SKILL.md
@@ -5,10 +5,11 @@ description: >-
Vite plugin, StartClient, StartServer, Vue-specific setup,
re-exports from @tanstack/start-client-core. Full project setup
with Vue.
-type: framework
-library: tanstack-start
-library_version: '1.166.2'
-framework: vue
+metadata:
+ type: framework
+ library: tanstack-start
+ library_version: '1.166.2'
+ framework: vue
requires:
- start-core
sources: