# @repo/api-client -- Framework-Agnostic tRPC + React Query Provider ## Purpose This package provides a framework-agnostic tRPC client and React Query provider that any frontend app (Next.js, TanStack Start, or future frameworks) can consume. It exposes `` for initialization and `useTRPC()` for fully typed data fetching. It contains zero business logic. ## Hard Rules - **NEVER** import framework-specific code (no `next/`, no `@tanstack/start`, no `vinxi/`) - **NEVER** put business logic in this package - **NEVER** create custom hooks that duplicate what `useTRPC()` already provides - Both Next.js and TanStack Start apps use the same `` and `useTRPC()` - This package depends on `@repo/api` for the `AppRouter` type only (no runtime import) ## File Structure ``` packages/api-client/ src/ trpc.ts # Creates TRPCProvider + useTRPC via createTRPCContext() query-client.ts # Singleton QueryClient factory (SSR-safe) provider.tsx # component: wires tRPC client + QueryClientProvider index.ts # Package entry: re-exports ApiProvider, useTRPC, getQueryClient package.json AGENTS.md ``` ## How Apps Consume This Package ### Step 1: Wrap your app with `` The provider needs a `trpcUrl` pointing to the tRPC HTTP endpoint: ```tsx // apps/web-next/src/app/providers.tsx "use client"; import { ApiProvider } from "@repo/api-client"; export function Providers({ children }: { children: React.ReactNode }) { return {children}; } ``` ```tsx // apps/web-next/src/app/layout.tsx import { Providers } from "./providers"; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` For TanStack Start, the provider goes in the root route: ```tsx // apps/web-tanstack/src/routes/__root.tsx import { Outlet, createRootRoute } from "@tanstack/react-router"; import { ApiProvider } from "@repo/api-client"; export const Route = createRootRoute({ component: () => ( ), }); ``` ### Step 2: Use `useTRPC()` in components ```tsx "use client"; import { useTRPC } from "@repo/api-client"; import { useQuery, useMutation } from "@tanstack/react-query"; export function ArticleList() { const trpc = useTRPC(); // Query -- reads data const { data, isLoading, error } = useQuery( trpc.content.listArticles.queryOptions({ status: "published", limit: 10 }) ); // Mutation -- writes data const createArticle = useMutation( trpc.content.createArticle.mutationOptions() ); if (isLoading) return

Loading...

; if (error) return

Error: {error.message}

; return (
    {data?.map((article) => (
  • {article.title}
  • ))}
); } ``` ## The `useTRPC()` Pattern `useTRPC()` is created by `createTRPCContext()` from `@trpc/tanstack-react-query`. It returns a proxy object that mirrors the router structure: ``` useTRPC() .auth .signIn.mutationOptions() .signUp.mutationOptions() .signOut.mutationOptions() .content .listArticles.queryOptions({ ... }) .createArticle.mutationOptions() ``` You pass `.queryOptions()` to `useQuery()` and `.mutationOptions()` to `useMutation()` from `@tanstack/react-query`. This gives you full control over caching, refetching, optimistic updates, and all React Query features. ## Custom Hook Wrappers Are Optional Since `useTRPC()` gives fully typed access to every procedure, you do **not** need to create wrapper hooks like `useArticles()`. Only create a custom hook if you have shared logic (e.g., combining multiple queries, adding retry logic, or transforming results) that would otherwise be duplicated across multiple components. ## QueryClient Configuration The `getQueryClient()` factory in `query-client.ts` handles SSR correctly: - **Server-side:** Creates a new `QueryClient` per request (avoids cross-request data leaks) - **Client-side:** Returns a singleton `QueryClient` (reused across renders) - Default `staleTime` is 30 seconds ## Dependencies | Dependency | Purpose | |---|---| | `@repo/api` | `AppRouter` type for end-to-end type safety (type-only import) | | `@trpc/client` | tRPC client with `httpBatchLink` | | `@trpc/tanstack-react-query` | `createTRPCContext` for React Query integration | | `@tanstack/react-query` | `QueryClient`, `QueryClientProvider` | | `react` | JSX runtime for provider component | ## Cross-References - **Router types come from:** `packages/api/` -- see `packages/api/AGENTS.md` - **tRPC HTTP endpoint:** `apps/web-next/src/app/api/trpc/[trpc]/route.ts` - **Provider usage in Next.js:** `apps/web-next/src/app/providers.tsx` - **Provider usage in TanStack:** `apps/web-tanstack/src/routes/__root.tsx`