new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

tRPC · all subjects

setup/nextjs-app-router

66 notes in this subject, read out of this brain and free to use. This is page 1 of 2.

shouldDehydrateQuery configuration for pending queries

Extend the defaultShouldDehydrateQuery function to include queries with status 'pending' in the dehydrate options. This allows prefetching to begin in a server component high in the tree, with the promise being consumed in a client component further down, as the RSC transport protocol supports hydrating promises over the network.

Data transformer configuration for QueryClient

If a data transformer (like superjson) is set up on the server, set the serializeData and deserializeData options in the QueryClient's dehydrate and hydrate sections to ensure data is serialized correctly when hydrating across the server-client boundary.

Creating tRPC client for client components

Use createTRPCClient with httpBatchLink to create a type-safe client. Import the AppRouter type from the server routers and pass it as the generic type. The client should be created inside the TRPCReactProvider component using useState to ensure the same instance persists across renders.

Sharing data between server and client with fetchQuery

Use queryClient.fetchQuery instead of prefetchQuery if you need to access data in a server component and also have it available in client components. This stores the data in the cache and hydrates it to the client, but understand the tradeoffs explained in TanStack React Query's Advanced Server Rendering guide regarding data ownership and revalidation.

Creating tRPC context in App Router

Create a createTRPCContext function that accepts an object with a headers property of type Headers. This function should be reusable in both RSC server caller (using next/headers) and API route handlers (using request headers). The context is then passed to initTRPC when creating the t object using .context<Awaited<ReturnType<typeof createTRPCContext>>>().

QueryClient staleTime configuration for SSR

Set staleTime to a value above 0 (e.g., 30 * 1000 milliseconds) in the default query options when using SSR to avoid refetching immediately on the client.

TRPCReactProvider implementation

Export TRPCProvider and useTRPC from createTRPCContext<AppRouter>(). The TRPCReactProvider component wraps QueryClientProvider and TRPCProvider. It should handle creating the query client and tRPC client, with special handling to avoid recreating the query client if React suspends during initial render. Avoid using useState when initializing the query client if there is no suspense boundary between the initialization and code that may suspend.

URL construction in TRPCReactProvider

The getUrl function should return an empty string when running in the browser (typeof window !== 'undefined'), use https://{process.env.VERCEL_URL} when deployed to Vercel, and default to http://localhost:3000 for local development. The final URL appends /api/trpc.

Creating tRPC server caller for server components

Use createTRPCOptionsProxy to create a server-side caller proxy. Pass an async ctx function that returns createTRPCContext with headers from next/headers, the app router, and a queryClient getter. Use React's cache function to create a stable getQueryClient getter that returns the same client during the same request. Alternatively, if the router is on a separate server, pass a client created with httpLink instead of ctx and router.

Server-only module protection

Import 'server-only' at the top of the server.tsx file to ensure it cannot be imported from the client.

Helper functions for prefetching and hydration

Create prefetch and HydrateClient helper functions to simplify the pattern. The prefetch function takes query options and prefetches them, detecting infinite queries by checking queryOptions.queryKey[1]?.type === 'infinite' and using prefetchInfiniteQuery for those. HydrateClient wraps children with HydrationBoundary and dehydrated query client state.

Using Suspense with tRPC queries

Use useSuspenseQuery hook instead of useQuery to handle loading and error states with Suspense and Error Boundaries. Wrap the client component with Suspense boundaries in the parent server component.

Direct server-side calling with createCaller

Use appRouter.createCaller() to create a server caller that can be used directly in server components without involving the query client. Pass an async function that returns the tRPC context. This method is detached from the query client and does not store data in the cache, so data cannot be shared between server and client components using this method.

Next.js App Router SSE chat example

A starter project demonstrating Next.js App Router with SSE-based subscriptions and chat functionality. Uses @trpc/react-query with the fetch adapter. Can be cloned with: npx create-next-app --example https://github.com/trpc/trpc/tree/main/examples/next-sse-chat trpc-sse-chat

tRPC bootstrapper projects

Official and community bootstrapper projects include: create-t3-app (Next.js, tRPC, Tailwind CSS, Prisma), sidebase (Nuxt 3, tRPC, Tailwind CSS, Prisma), Create tRPC App, viteRPC (Vite monorepo template), and Start UI web (Next.js, tRPC, Prisma, Chakra UI).

tRPC recommended starter projects

Official tRPC example projects include: Next.js + Prisma starter with E2E testing, create-t3-turbo with Expo React Native, SSE Subscriptions starter, WebSockets starter, and tRPC Kitchen Sink collection of usage patterns.

VSCode TypeScript version settings

To ensure VSCode uses the same TypeScript version as your package.json, add these settings to .vscode/settings.json: {"typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true}. It is recommended to commit this file to the repository so colleagues get the same experience.

TypeScript version requirement for tRPC

tRPC requires TypeScript version 5.7.2 or higher.

Strict mode requirement in tsconfig.json

tRPC requires "strict": true to be set in your tsconfig.json configuration for proper type inference.

Matching @trpc versions across projects

All @trpc/* package versions must match in your package.json to avoid type inference issues.

Monorepo not mandatory

A monorepo is not mandatory for tRPC, but using one provides benefits like guarantees that client and server work together. Without a monorepo, one approach is to publish a private npm package with backend types for consumption in the frontend.

Monorepo troubleshooting for tRPC

When tRPC doesn't work in a monorepo, check: all @trpc/* versions match across projects, "strict": true is set in all tsconfig.json files, there are no type errors, and if using separate server and client tsconfig.json files without a bundled server package, ensure the client tsconfig.json has "paths" matching the server tsconfig.json so the client can find the same files.

Troubleshooting getting 'any' types everywhere

If tRPC is showing 'any' types everywhere, check: no type errors exist in code, "strict": true is in tsconfig.json, all @trpc/* versions match in package.json, TypeScript version is 5.7.2 or higher, and the editor is using the same TypeScript version as package.json.

TypeScript version requirement for tRPC

tRPC requires TypeScript version 5.7.2 or higher. The use of "strict": true in tsconfig.json is strongly recommended as non-strict mode is not officially supported.

tRPC v11 installation packages

Install the following packages for tRPC v11: @trpc/server@^11, @trpc/client@^11, @trpc/react-query@^11, @trpc/next@^11, @tanstack/react-query@^5, and @tanstack/react-query-devtools@^5.

TypeScript version requirement

tRPC v11 requires TypeScript version 5.7.2 or higher. Attempting to install with an unsupported TypeScript version will result in a peer dependency error. If the editor shows any types, configure it to use the TypeScript version in the project's package.json. For VSCode, add to .vscode/settings.json: {"typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true}.

interop mode removed

The interop mode has been completely removed from tRPC v11. This was a transition mode from v9 to v10 that was never intended for long-term support.

AbortControllerEsque ponyfill removed

The AbortControllerEsque ponyfill has been removed from tRPC. Use a polyfill like abortcontroller-polyfill if you need to support older browsers.

NodeJS 18+ and modern browsers required

tRPC v11 requires NodeJS 18 or higher and modern browsers. Usage of FormData, File, Blob, and ReadableStream APIs has been added.

React 18.2.0+ required

tRPC v11 requires React version 18.2.0 or higher. Refer to the React migration guide at https://react.dev/blog/2022/03/08/react-18-upgrade-guide.

Replace createTRPCReact with createTRPCContext

Replace the classic `createTRPCReact` function with `createTRPCContext` from the new package. The old pattern `import { createTRPCReact } from '@trpc/react-query'; export const trpc = createTRPCReact<AppRouter>();` becomes `import { createTRPCContext } from '@trpc/tanstack-react-query'; export const { TRPCProvider, useTRPC } = createTRPCContext<AppRouter>();`.

Nest TRPCProvider inside QueryClientProvider

Update the provider setup in the app root. Wrap the application with QueryClientProvider containing TRPCProvider inside it. The pattern is `<QueryClientProvider client={queryClient}><TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>{children}</TRPCProvider></QueryClientProvider>`.

TanStack React Query setup installation command

Install the required packages with: npm install @trpc/server @trpc/client @trpc/tanstack-react-query @tanstack/react-query

TanStack React Query setup with createTRPCContext

Use createTRPCContext from '@trpc/tanstack-react-query' to create TRPCProvider, useTRPC, and useTRPCClient hooks. The function accepts the AppRouter type as a generic parameter: export const { TRPCProvider, useTRPC, useTRPCClient } = createTRPCContext<AppRouter>();

Next.js App Router file structure

The recommended tRPC + Next.js App Router file structure includes: app/api/trpc/[trpc]/route.ts for the HTTP handler, app/layout.tsx to mount TRPCReactProvider, app/page.tsx for server components with prefetch, and app/client-greeting.tsx for client components. Server-side code goes in trpc/init.ts for context setup, trpc/routers/_app.ts for the main router, trpc/query-client.ts for QueryClient factory, trpc/client.tsx for client hooks and provider, and trpc/server.tsx for server-side proxy and helpers.

Install dependencies for Next.js App Router with tRPC

npm install @trpc/server @trpc/client @trpc/tanstack-react-query @tanstack/react-query zod server-only client-only

Create tRPC context and init in trpc/init.ts

The trpc/init.ts file should import initTRPC, define createTRPCContext as an async function that receives opts with Headers and returns context data (e.g., userId), then call initTRPC.context<Awaited<ReturnType<typeof createTRPCContext>>>().create() to instantiate the tRPC instance. Export createTRPCRouter, createCallerFactory, and baseProcedure from this instance.

Define tRPC router in trpc/routers/_app.ts

Create the main app router using createTRPCRouter and export it as appRouter. Define procedures with baseProcedure, add input validation with z.object(), and specify query or mutation handlers. Export type AppRouter = typeof appRouter for end-to-end type inference.

QueryClient factory with dehydration config for RSC

Create a makeQueryClient function that returns a new QueryClient with defaultOptions.queries.staleTime set (e.g., 30 * 1000). In defaultOptions.dehydrate.shouldDehydrateQuery, call defaultShouldDehydrateQuery(query) || query.state.status === 'pending' to ensure pending queries are included in dehydration for RSC hydration. If using a data transformer like superjson, add dehydrate.serializeData and hydrate.deserializeData configuration.

TRPCReactProvider client component setup

In trpc/client.tsx marked with 'use client', import createTRPCContext from @trpc/tanstack-react-query and createTRPCClient with httpBatchLink from @trpc/client. Call createTRPCContext<AppRouter>() to get TRPCProvider, useTRPC, and useTRPCClient. Implement getQueryClient to return makeQueryClient() and cache it in browserQueryClient singleton for the browser only. Implement getUrl to return '/api/trpc' relative path in browser, or construct full URL with VERCEL_URL or localhost:3000 on server. Create TRPCReactProvider component that wraps children in QueryClientProvider and TRPCProvider with createTRPCClient configured with httpBatchLink.

Server-side RSC proxy with createTRPCOptionsProxy

In trpc/server.tsx marked with 'server-only', import dehydrate and HydrationBoundary from @tanstack/react-query, createTRPCOptionsProxy from @trpc/tanstack-react-query, and cache from react. Create getQueryClient using cache(makeQueryClient) to ensure one QueryClient per request. Use createTRPCOptionsProxy with ctx async function that calls createTRPCContext with headers, and pass router and queryClient. Export trpc object for use in server components. Provide a prefetch helper that checks queryOptions.queryKey[1]?.type for 'infinite' and calls prefetchInfiniteQuery or prefetchQuery accordingly.

HydrateClient component for RSC data hydration

The HydrateClient component exported from trpc/server.tsx wraps children in HydrationBoundary with state={dehydrate(getQueryClient())} to transfer server-prefetched query state to the client.

Mount TRPCReactProvider in root layout

In app/layout.tsx, import TRPCReactProvider from trpc/client and wrap the children with <TRPCReactProvider>{children}</TRPCReactProvider> inside the layout component.

Prefetch query in server component and consume in client component

In a server component (e.g., app/page.tsx), import prefetch, trpc, and HydrateClient from trpc/server. Call prefetch(trpc.hello.queryOptions({ text: 'world' })) to prefetch data server-side. Wrap the client component with HydrateClient which dehydrates the prefetched query state. In the client component marked with 'use client', import useTRPC and useQuery from @tanstack/react-query. Call const trpc = useTRPC() and then useQuery(trpc.hello.queryOptions({ text: 'world' })) to consume the hydrated data with instant availability.

useSuspenseQuery with Suspense boundary for RSC

To use Suspense for server-rendered queries, wrap the server component call with Suspense and ErrorBoundary. In app/page.tsx, call prefetch with the query options, then wrap the client component in Suspense with a fallback. In the client component, import useSuspenseQuery from @tanstack/react-query and call const { data } = useSuspenseQuery(trpc.hello.queryOptions({ text: 'world' })) to access the data directly without checking loading state. The Suspense boundary shows the fallback until data resolves.

Direct server caller for server-only data

Export a caller from trpc/server.tsx using export const caller = appRouter.createCaller(async () => createTRPCContext({ headers: await headers() })). In a server component, import caller and invoke procedures directly: const greeting = await caller.hello({ text: 'world' }). Caller results are not stored in the query cache and cannot hydrate to client components. Use prefetchQuery if client components also need the data.

fetchQuery for server and client data access

In a server component, call const queryClient = getQueryClient() and then const greeting = await queryClient.fetchQuery(trpc.hello.queryOptions({ text: 'world' })). This stores the result in the query cache so it can be used on the server and hydrated to client components. Data is available for logging or server-side use, and is transferred to the client via HydrateClient.

Export both GET and POST from route handler

The route handler in app/api/trpc/[trpc]/route.ts must export both GET and POST as named exports. Missing either export causes Next.js to return 405 Method Not Allowed for that HTTP method. Correct pattern: const handler = (req: Request) => fetchRequestHandler({ ... }); export { handler as GET, handler as POST }.

Never create singleton QueryClient for SSR

In server components, each request must have its own QueryClient instance. A singleton QueryClient shared across requests will leak data between requests. Use cache(makeQueryClient) to ensure a fresh QueryClient per request, with the same instance reused within a single request.

Must configure shouldDehydrateQuery for pending queries

RSC hydration requires shouldDehydrateQuery to include pending queries. Without including query.state.status === 'pending' in shouldDehydrateQuery, prefetched-but-not-yet-resolved promises will not appear in the hydrated state on the client, breaking the expected data flow from server to client.

useSuspenseQuery errors crash entire page during SSR

If a query fails during SSR with useSuspenseQuery, the entire page crashes. Error Boundaries only catch errors on the client side, not on the server. For critical pages, either handle errors server-side before rendering the component, or use useQuery (non-suspense) which allows graceful degradation.

Minimal React example requires Node 18

The minimal React tRPC example requires Node 18 or later, specifically for global fetch support.

Minimal React example setup commands

To set up the minimal React tRPC example, run npm i to install dependencies, then npm run dev to start the development server.

Minimal React example build and start

To build the minimal React tRPC example, run npm run build followed by npm run start to start the production server.

Next.js minimal starter example setup

To set up the Next.js minimal tRPC starter, run npx create-next-app --example https://github.com/trpc/trpc --example-path examples/next-minimal-starter trpc-minimal-starter, then cd into the directory, run npm i to install dependencies, and npm run dev to start development.

Run Next.js tRPC development server

Start the development server for a Next.js tRPC project by running npm run dev, which starts the Next.js development server.

TodoMVC example setup command

To set up the TodoMVC example project, run: pnpm create next-app --example https://github.com/trpc/trpc --example-path examples/next-prisma-todomvc trpc-todo, then cd trpc-todo, then pnpm, then pnpm dev.

TodoMVC dx command

The command pnpm dx runs Prisma Studio and Next.js concurrently for the TodoMVC example project.

TodoMVC example stack

The TodoMVC example is implemented with tRPC and Prisma, demonstrating a complete full-stack application.

next-prisma-starter example project setup

The next-prisma-starter is a tRPC example project that demonstrates E2E typesafety with tRPC, full-stack React with Next.js, and database with Prisma. It can be created using: pnpm create next-app --example https://github.com/trpc/trpc --example-path examples/next-prisma-starter trpc-prisma-starter

Give your agent this brain