TanStack Start conventions
Stack conventions for TanStack Start apps in this org. Requires skill tanstack-router-conventions (search params, pretty URLs, loaders + Query, typed Router TS, devtools). Pair with tanstack-start-auth for auth and session layout.
When to apply
- Scaffolding or refactoring
app/src folder layout (see app-structure.md)
- Splitting code between
.server.ts and .functions.ts
createServerFn, server mutations, form submit / invalidation
- Setting route
ssr or debugging SSR / hydration
- Using server components (
renderServerComponent, createCompositeComponent)
- API routes under
routes/api/ (handler-only; search validation in GET)
Router / SPA topics (validateSearch, parseSearch / stringifySearch, loader + Query defaults) → install and follow tanstack-router-conventions — do not duplicate them here.
App structure (src)
Folder layout, thin routes, Layout/Page naming, and test layout: app-structure.md. For project-specific paths, use the repo's local docs/ file.
Reference reading order
- Prerequisite: skill
tanstack-router-conventions (search serialization, UI validateSearch, ?map=, router + Query, TypeScript, devtools)
- app-structure.md —
src folders, thin routes, Layout/Page naming, tests
- local-runtime.md —
bun --bun for Vite + Nitro so local SSR matches production Bun
- execution-model.md — isomorphic execution, loaders on soft nav, server fn boundary
- client-server-boundaries.md — file suffixes, import protection,
beforeLoad vs loader
- server-functions.md —
createServerFn API, validation, form submit, invalidation
- params-search-api-routes.md — Zod in API
GET (no route-level validateSearch)
- selective-ssr.md —
ssr: true / 'data-only' / false (handler-only API routes: false)
- server-components.md — experimental RSC: FMC conventions, official doc map, selective SSR pairing
Auth-specific flows: skill tanstack-start-auth.
Non-negotiable rules
| Topic |
Rule |
| Server-only modules |
*.server.ts — never imported by routes/components; use createServerOnlyFn inside |
| Callable from client |
*.functions.ts with createServerFn; name exports *Fn |
| Public server fns |
public*.functions.ts — no global auth middleware; rate-limit/token checks in .server.ts (see tanstack-start-auth) |
| API route files |
No server-only import marker on the route file; server-only logic inside handlers or tree-shaken imports |
| API search params |
Do not use validateSearch on API routes; safeParse in GET from request.url with explicit 4xx JSON — params-search-api-routes.md |
| SSR |
Set ssr explicitly on every route; UI default full SSR (true); handler-only API routes: false; map-heavy UI: data-only |
| Local Bun runtime |
Vite dev and Nitro start/preview use bun --bun so SSR matches production preset: bun — local-runtime.md |
| Router search / Query |
Owned by tanstack-router-conventions — Start apps still must follow that skill’s parseSearch / stringifySearch and loader + Query rules |
Quick decisions
beforeLoad vs loader: Redirects, auth, light context → beforeLoad (not middleware). Data fetch / Query priming → loader. Caveat: beforeLoad is not gated by loaderDeps — it re-runs on every navigation, search-param changes included. On hot routes with client-only search params (map viewport, layer toggles), move the redirect/auth/region round-trip into the loader and keep those params out of loaderDeps so they stay client-only (no round-trip, no pending). See client-server-boundaries.md.
Loader vs Query: Follow tanstack-router-conventions → router-and-query.md. On Start, route server I/O through createServerFn (execution-model.md).
ssr: Map/canvas-heavy UI but need server auth/data → 'data-only'. Handler-only API (server.handlers) → false. Fully client-first UI route → false (rare).
Server components (experimental): Opt-in RSC layer — not the default FMC data path. See server-components.md.
Related skills
| Topic |
Skill |
| Router (required) |
tanstack-router-conventions |
| Auth / session |
tanstack-start-auth |
| Bun install / nvm |
tech-stack → bun-install |
| Zustand |
zustand-state-management |
| nuqs (Next.js) |
nuqs |
| Leftover placement after refactors |
unslop-code Phase 6 → component-location.md |
1---2name: tanstack-start-conventions3description: TanStack Start conventions for FixMyBerlin/FMC: app folder layout, thin routes, client/server file suffixes, createServerFn, selective SSR, experimental RSC, and API route param/search validation. Requires tanstack-router-conventions for validateSearch, search serialization, and loader + Query patterns. Use when scaffolding or refactoring Start apps, server functions, SSR, renderServerComponent, or API routes under routes/api/.4---56# TanStack Start conventions78Stack conventions for **TanStack Start** apps in this org. **Requires** skill `tanstack-router-conventions` (search params, pretty URLs, loaders + Query, typed Router TS, devtools). Pair with `tanstack-start-auth` for auth and session layout.910## When to apply1112- Scaffolding or refactoring `app/src` folder layout (see [app-structure.md](references/app-structure.md))13- Splitting code between `.server.ts` and `.functions.ts`14- `createServerFn`, server mutations, form submit / invalidation15- Setting route `ssr` or debugging SSR / hydration16- Using server components (`renderServerComponent`, `createCompositeComponent`)17- API routes under `routes/api/` (handler-only; search validation in `GET`)1819**Router / SPA topics** (`validateSearch`, `parseSearch` / `stringifySearch`, loader + Query defaults) → install and follow `tanstack-router-conventions` — do not duplicate them here.2021## App structure (`src`)2223Folder layout, thin routes, Layout/Page naming, and test layout: [app-structure.md](references/app-structure.md). For project-specific paths, use the repo's local `docs/` file.2425## Reference reading order26270. **Prerequisite:** skill `tanstack-router-conventions` (search serialization, UI `validateSearch`, `?map=`, router + Query, TypeScript, devtools)281. [app-structure.md](references/app-structure.md) — `src` folders, thin routes, Layout/Page naming, tests292. [local-runtime.md](references/local-runtime.md) — `bun --bun` for Vite + Nitro so local SSR matches production Bun303. [execution-model.md](references/execution-model.md) — isomorphic execution, loaders on soft nav, server fn boundary314. [client-server-boundaries.md](references/client-server-boundaries.md) — file suffixes, import protection, `beforeLoad` vs `loader`325. [server-functions.md](references/server-functions.md) — `createServerFn` API, validation, form submit, invalidation336. [params-search-api-routes.md](references/params-search-api-routes.md) — Zod in API `GET` (no route-level `validateSearch`)347. [selective-ssr.md](references/selective-ssr.md) — `ssr: true` / `'data-only'` / `false` (handler-only API routes: `false`)358. [server-components.md](references/server-components.md) — experimental RSC: FMC conventions, official doc map, selective SSR pairing3637Auth-specific flows: skill `tanstack-start-auth`.3839## Non-negotiable rules4041| Topic | Rule |42| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |43| Server-only modules | `*.server.ts` — never imported by routes/components; use `createServerOnlyFn` inside |44| Callable from client | `*.functions.ts` with `createServerFn`; name exports `*Fn` |45| Public server fns | `public*.functions.ts` — no global auth middleware; rate-limit/token checks in `.server.ts` (see `tanstack-start-auth`) |46| API route files | No `server-only` import marker on the route file; server-only logic inside handlers or tree-shaken imports |47| API search params | Do **not** use `validateSearch` on API routes; `safeParse` in `GET` from `request.url` with explicit 4xx JSON — [params-search-api-routes.md](references/params-search-api-routes.md) |48| SSR | Set `ssr` explicitly on every route; UI default full SSR (`true`); handler-only API routes: `false`; map-heavy UI: `data-only` |49| Local Bun runtime | Vite `dev` and Nitro `start`/`preview` use `bun --bun` so SSR matches production `preset: bun` — [local-runtime.md](references/local-runtime.md) |50| Router search / Query | Owned by `tanstack-router-conventions` — Start apps still **must** follow that skill’s `parseSearch` / `stringifySearch` and loader + Query rules |5152## Quick decisions5354**`beforeLoad` vs `loader`:** Redirects, auth, light context → `beforeLoad` (not middleware). Data fetch / Query priming → `loader`. **Caveat:** `beforeLoad` is not gated by `loaderDeps` — it re-runs on **every** navigation, search-param changes included. On hot routes with client-only search params (map viewport, layer toggles), move the redirect/auth/region round-trip into the `loader` and keep those params out of `loaderDeps` so they stay client-only (no round-trip, no pending). See [client-server-boundaries.md](references/client-server-boundaries.md).5556**Loader vs Query:** Follow `tanstack-router-conventions` → `router-and-query.md`. On Start, route server I/O through `createServerFn` ([execution-model.md](references/execution-model.md)).5758**`ssr`:** Map/canvas-heavy UI but need server auth/data → `'data-only'`. Handler-only API (`server.handlers`) → `false`. Fully client-first UI route → `false` (rare).5960**Server components (experimental):** Opt-in RSC layer — not the default FMC data path. See [server-components.md](references/server-components.md).6162## Related skills6364| Topic | Skill |65| ---------------------------------- | ------------------------------------------------------------------------------------------------ |66| Router (required) | `tanstack-router-conventions` |67| Auth / session | `tanstack-start-auth` |68| Bun install / nvm | `tech-stack` → bun-install |69| Zustand | `zustand-state-management` |70| nuqs (Next.js) | `nuqs` |71| Leftover placement after refactors | `unslop-code` Phase 6 → [component-location.md](../unslop-code/references/component-location.md) |