Files
agentic-dev-template/apps/web-tanstack/AGENTS.md

4.8 KiB

apps/web-tanstack -- TanStack Start Reference App

Purpose

TanStack Start reference application using TanStack Router with file-based routing. Demonstrates how to consume @repo/api-client for tRPC data fetching and @repo/ui for components. Like apps/web-next, this is a thin app -- business logic lives in @repo/core, UI components live in @repo/ui.

Port: 3002

pnpm dev --filter @repo/web-tanstack   # http://localhost:3002

Key Files

File Purpose
src/routes/__root.tsx Root layout -- creates the root route, wraps with <ApiProvider> and <Outlet>
src/routes/index.tsx Home page route (/)

File-Based Routing

TanStack Router uses file-based routing where file paths in src/routes/ map directly to URL paths:

File URL Description
src/routes/__root.tsx (all routes) Root layout, wraps all child routes
src/routes/index.tsx / Home page
src/routes/about.tsx /about Static page
src/routes/articles/index.tsx /articles Article listing
src/routes/articles/$id.tsx /articles/:id Single article (dynamic param)

Naming conventions:

  • __root.tsx -- special root layout file, always wraps all routes
  • index.tsx -- index route for its directory (e.g., /articles/index.tsx matches /articles)
  • $paramName.tsx -- dynamic route segment (e.g., $id.tsx captures :id)
  • Nested folders create nested URL segments

Provider Setup

The <ApiProvider> wraps the entire app in __root.tsx:

// src/routes/__root.tsx
import { Outlet, createRootRoute } from "@tanstack/react-router";
import { ApiProvider } from "@repo/api-client";

export const Route = createRootRoute({
  component: () => (
    <ApiProvider trpcUrl="http://localhost:3000/api/trpc">
      <Outlet />
    </ApiProvider>
  ),
});

Note: The trpcUrl points to the Next.js app's tRPC endpoint at http://localhost:3000/api/trpc. In production, this should be configured via environment variables.

Recipe: Adding a New Route with Data Fetching

This example adds an /articles route that lists published articles.

Step 1: Create the route file

Create src/routes/articles/index.tsx:

import { createFileRoute } from "@tanstack/react-router";
import { useTRPC } from "@repo/api-client";
import { useQuery } from "@tanstack/react-query";
import { Button } from "@repo/ui";

export const Route = createFileRoute("/articles/")({
  component: ArticlesPage,
});

function ArticlesPage() {
  const trpc = useTRPC();
  const { data, isLoading, error } = useQuery(
    trpc.content.listArticles.queryOptions({ status: "published", limit: 20 })
  );

  if (isLoading) return <p>Loading articles...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <main>
      <h1>Articles</h1>
      <ul>
        {data?.map((article) => (
          <li key={article.id}>
            <h2>{article.title}</h2>
            <Button variant="outline" size="sm">
              Read more
            </Button>
          </li>
        ))}
      </ul>
    </main>
  );
}

Step 2: Add a dynamic route for individual articles

Create src/routes/articles/$id.tsx:

import { createFileRoute } from "@tanstack/react-router";
import { useTRPC } from "@repo/api-client";
import { useQuery } from "@tanstack/react-query";

export const Route = createFileRoute("/articles/$id")({
  component: ArticlePage,
});

function ArticlePage() {
  const { id } = Route.useParams();
  const trpc = useTRPC();

  // Use the article ID from the URL parameter
  // (Assuming a getArticle procedure exists on the content router)
  const { data, isLoading } = useQuery(
    trpc.content.listArticles.queryOptions({ limit: 1 })
  );

  if (isLoading) return <p>Loading...</p>;

  return (
    <main>
      <h1>Article {id}</h1>
    </main>
  );
}

Key patterns:

  • Every route file exports a Route created via createFileRoute(path)(...)
  • The component property defines the React component for that route
  • Use Route.useParams() to access dynamic parameters (e.g., $id)
  • Data fetching uses the same useTRPC() + useQuery() pattern as Next.js
  • Import UI components from @repo/ui, never recreate them locally

Dependencies

Dependency Purpose
@repo/api AppRouter type (transitive via @repo/api-client)
@repo/api-client ApiProvider + useTRPC() for client-side data fetching
@repo/ui Shared UI components
@tanstack/react-router TanStack Router for file-based routing
react / react-dom React 19 runtime

Cross-References

  • tRPC routers: packages/api/ -- see packages/api/AGENTS.md
  • tRPC client/hooks: packages/api-client/ -- see packages/api-client/AGENTS.md
  • UI components: packages/ui/ -- see packages/ui/AGENTS.md
  • Next.js app (serves the tRPC endpoint): apps/web-next/ -- see apps/web-next/AGENTS.md