agentleFS
htmujahidhtmujahid/project-structure-skills/skills/tanstack-router-architecture/SKILL.md

tanstack-router-architecture

Skill0 starsChanged 16 days agoMITView on GitHub

Use when creating, moving, or naming files in a frontend-only TanStack Router app (Vite SPA, file-based routes) that also uses TanStack Query, Form, Table, DB, and Devtools, organized by technical layer. Backend is out of scope. Covers routes, components, lib/queries, lib/mutations, lib/collections, import direction, tests, and growth. For full-stack, use tanstack-start-architecture.

  • Reads credentials

The file

Show its rules and text

We split this skill into the rules it gives an agent

20 rules. About 0 are common, 8 are distinctive, and 12 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈8

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 12

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Read src/ before creating files.

    line 17
  2. Distinctive:

    Read references/full-tree.md when you need the expanded tree.

    line 53
  3. Distinctive:

    Add a folder on first use.

    line 55
  4. Very specific:

    Keep a component in the route's -components/ until a second route uses it, then move it to components/.

    line 56
  5. Very specific:

    Put tests next to the file.

    line 92
  6. Distinctive:

    Test queries, mutations, and utils without rendering.

    line 93
  7. Very specific:

    Put end-to-end tests in e2e/ at the repo root.

    line 94
  8. Distinctive:

    Read references/growth-stages.md when deciding whether to restructure.

    line 98
  9. Very specific:

    Use routes/, components/, and lib/.

    line 102
  10. Very specific:

    Use the default layout. Past about 10 files in a layer, group by resource inside it (lib/queries/billing/).

    line 106
  11. Very specific:

    Keep the layers. Group by feature inside each layer and mirror it in routes/.

    line 110
  12. Distinctive:

    Read references/anti-patterns.md when reviewing a layout or before moving files.

    line 114
  13. Very specific:

    Do not call fetch or the API client from a component.

    line 116
  14. Distinctive:

    Do not write query keys inline.

    line 117
  15. Very specific:

    Do not put data fetching in useEffect.

    line 118
  16. Very specific:

    Do not edit routeTree.gen.ts.

    line 119
  17. Very specific:

    Do not put non-route files in routes/ without a - prefix.

    line 120
  18. Very specific:

    Do not copy query data into useState or a store.

    line 121
  19. Distinctive:

    Do not put backend code in this app.

    line 122
  20. Distinctive:

    Do not use PascalCase file names.

    line 123

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

TanStack Router architecture

Client-only React app with TanStack Router (file-based routes) on Vite, grouped by technical role. Data code lives in lib/queries, lib/mutations, and lib/collections. The backend is a separate service and is out of scope: the app only calls it through lib/api/. For a full-stack app, use tanstack-start-architecture.

Target version

Written for TanStack Router v1 (file-based, @tanstack/router-plugin), TanStack Query v5, Form, Table, DB, and Devtools on 2026-10-30. TanStack DB moves fast, so check its installed version before copying patterns.

Follow the repo first

Read src/ before creating files. If the project already has conventions (folder names, casing, aliases), use them. Check vite.config.ts for the router plugin options (routesDirectory, code splitting) and tsconfig.json for aliases.

Default directory layout

src/
  main.tsx              # mounts <RouterProvider />
  router.tsx            # createRouter, context ({ queryClient }), defaults
  routeTree.gen.ts      # generated by the plugin. Commit it. Never edit it.
  routes/               # file-based routes, thin
    __root.tsx          # root layout, providers, devtools
    index.tsx
    invoices/
      route.tsx         # layout and loader for /invoices
      index.tsx
      $invoiceId.tsx
      -components/      # route-private UI (the - prefix is ignored by the router)
  components/           # shared UI used by 2+ routes
    ui/                 # primitives (Button, Dialog)
    forms/              # TanStack Form field components
    tables/             # TanStack Table wrappers and column helpers
    providers/          # query provider, theme, devtools
  hooks/                # shared UI hooks (useDebounce, useInvoiceTable)
  lib/
    queries/            # query keys and queryOptions, one file per resource
    mutations/          # mutationOptions and useMutation hooks
    collections/        # TanStack DB collections and live-query helpers
    api/                # HTTP client and request functions for the backend
    forms/              # createFormHook setup and shared validators
    schemas/            # zod (or similar) schemas for forms and responses
    auth/               # session helpers, route guards
    utils/              # pure helpers
  config/               # env parsing and constants
  types/  styles/  test/

Read references/full-tree.md when you need the expanded tree. Read references/data-layer.md when writing queries, mutations, collections, loaders, forms, or tables.

  • Add a folder on first use. Do not create empty ones.
  • Keep a component in the route's -components/ until a second route uses it, then move it to components/.
  • Route files do routing only: path, loader, search schema, and composing components.

Naming conventions

  • Files and folders: kebab-case. Route files follow router conventions ($param, _pathless, route.tsx, index.tsx, -private).
  • Components: InvoiceTable in invoice-table.tsx. Named exports, except route files, which export Route.
  • Queries: invoice.queries.ts, exporting invoiceKeys, invoiceListOptions, invoiceDetailOptions.
  • Mutations: invoice.mutations.ts, exporting useCreateInvoice, useDeleteInvoice.
  • Collections: invoice.collection.ts, exporting invoiceCollection.
  • API: invoice.api.ts. Schemas: invoice.schema.ts. Types: invoice.types.ts. Hooks: use-thing.ts.
  • Tests: invoice-table.test.tsx next to the file.
  • Imports: @/ maps to src/. Never use ../../...

Dependency direction

routes -> components -> hooks -> lib/{queries,mutations,collections} -> lib/api -> lib/{schemas,utils}
  • routes may import any layer below.
  • components import hooks, lib, and other components. Never routes.
  • lib/queries, lib/mutations, lib/collections call lib/api and lib/schemas. Never components or hooks.
  • lib/api imports config, lib/schemas, types. Only it calls the backend.
  • lib/utils and types import nothing from the app.

Where things live

  • Config: config/env.ts is the only place that reads import.meta.env. Prefix vars with VITE_. List them in .env.example.
  • Query client: create in router.tsx and pass through router context. Provider in components/providers/.
  • Devtools: mount Router, Query, and DB devtools in routes/__root.tsx or components/providers/devtools.tsx, dev only.
  • Global client state: prefer router search params and the query cache. Use a small store only for true UI state.
  • Auth guards: beforeLoad in a layout route (_authed/route.tsx), using lib/auth/.

Tests

  • Put tests next to the file. Put setup and helpers in test/.
  • Test queries, mutations, and utils without rendering. Test components with a router and query client wrapper.
  • Put end-to-end tests in e2e/ at the repo root.

Structure at three sizes

Read references/growth-stages.md when deciding whether to restructure.

Prototype

Use routes/, components/, and lib/. Add lib/queries on first API call.

Mid-size

Use the default layout. Past about 10 files in a layer, group by resource inside it (lib/queries/billing/).

Large

Keep the layers. Group by feature inside each layer and mirror it in routes/. Enforce boundaries with lint rules.

Anti-patterns

Read references/anti-patterns.md when reviewing a layout or before moving files.

  • Do not call fetch or the API client from a component. Use lib/queries or lib/mutations.
  • Do not write query keys inline. Use the key factory.
  • Do not put data fetching in useEffect. Use a loader plus ensureQueryData.
  • Do not edit routeTree.gen.ts.
  • Do not put non-route files in routes/ without a - prefix.
  • Do not copy query data into useState or a store.
  • Do not put backend code in this app.
  • Do not use PascalCase file names.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.