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 routesindex.tsx-- index route for its directory (e.g.,/articles/index.tsxmatches/articles)$paramName.tsx-- dynamic route segment (e.g.,$id.tsxcaptures: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
Routecreated viacreateFileRoute(path)(...) - The
componentproperty 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/-- seepackages/api/AGENTS.md - tRPC client/hooks:
packages/api-client/-- seepackages/api-client/AGENTS.md - UI components:
packages/ui/-- seepackages/ui/AGENTS.md - Next.js app (serves the tRPC endpoint):
apps/web-next/-- seeapps/web-next/AGENTS.md