Next.js Integration Overview
tRPC provides first-class support for both the App Router and the Pages Router in Next.js. The App Router is recommended for new projects, while the Pages Router is suitable for existing projects. tRPC enables type-safe data fetching by sharing types between client and server in a single codebase.
App Router key features
The App Router approach uses React Server Components, the fetch adapter, and @trpc/tanstack-react-query. Key features include Server Components for prefetching data on the server and streaming to the client, Next.js streaming for optimal loading performance, and Suspense with useSuspenseQuery for loading states.
Pages Router key features
The Pages Router uses @trpc/next which provides a higher-order component (HOC) and integrated hooks. Key features include server-side rendering to render pages on the server and hydrate them on the client, static site generation to prefetch queries on the server and generate static HTML files, and automatic provider wrapping via the @trpc/next HOC.
App Router vs Pages Router comparison table
Comparison of App Router and Pages Router: Recommended for: App Router - new projects, Pages Router - existing Pages Router projects. Data fetching: App Router - Server Components and prefetchQuery, Pages Router - getServerSideProps, getStaticProps, SSR via HOC. Server adapter: App Router - Fetch adapter, Pages Router - Next.js adapter. Client package: App Router - @trpc/tanstack-react-query, Pages Router - @trpc/next + @trpc/react-query. Provider setup: App Router - Manual QueryClientProvider + TRPCProvider, Pages Router - Automatic via withTRPC() HOC.
tRPC support for Next.js App Router and RSC
tRPC works with Next.js App Router and React Server Components. The Next.js App Router setup guide documents the recommended approach.
createCaller in Next.js API endpoint example
Example showing createCaller usage in a custom Next.js API endpoint:
```ts
import { TRPCError } from '@trpc/server';
import { getHTTPStatusCodeFromError } from '@trpc/server/http';
import { appRouter } from '../../server/routers/_app';
import type { NextApiRequest, NextApiResponse } from 'next';
type ResponseData = {
data?: { postTitle: string };
error?: { message: string };
};
export default async (
req: NextApiRequest,
res: NextApiResponse<ResponseData>,
) => {
const postId = `this-id-does-not-exist-${Math.random()}`;
const caller = appRouter.createCaller({});
try {
const postResult = await caller.post.byId({ id: postId });
res.status(200).json({ data: { postTitle: postResult.title } });
} catch (cause) {
if (cause instanceof TRPCError) {
const httpStatusCode = getHTTPStatusCodeFromError(cause);
res.status(httpStatusCode).json({ error: { message: cause.message } });
return;
}
res.status(500).json({ error: { message: `Error while accessing post with ID ${postId}` } });
}
};
```
tRPC Next.js Pages Router integration
Integrate tRPC with Next.js Pages Router using withTRPC higher-order component with SSR and SSG helpers. Refer to nextjs-pages-router skill for setup.
tRPC Next.js App Router integration
Use tRPC with Next.js App Router for React Server Components, server components, and HydrateClient patterns. Refer to nextjs-app-router skill for setup.
Next.js Pages Router file structure for tRPC
The file structure for tRPC with Next.js Pages Router includes: pages/_app.tsx with withTRPC() HOC, pages/api/trpc/[trpc].ts as the tRPC API handler, server/trpc.ts with initTRPC initialization, server/routers/_app.ts with the main app router, server/context.ts with createContext, and utils/trpc.ts with createTRPCNext and hooks.
Install dependencies for Next.js Pages Router with tRPC
Install @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query and zod.
Enable SSR with ssr: true in createTRPCNext
Set ssr: true and ssrPrepass in the createTRPCNext config. Requires ssrPrepass imported from @trpc/next/ssrPrepass. In config, differentiate between browser and server: on browser return links with /api/trpc, on server return links with full URL and forward cookie headers from ctx.req.headers.cookie.
Set up SSG with createServerSideHelpers and getStaticProps
In getStaticProps, create helpers with createServerSideHelpers passing router, ctx: {}, and transformer: superjson. Call helpers.procedureName.prefetch() to prefetch data. Return { props: { trpcState: helpers.dehydrate(), ...otherProps }, revalidate: 1 }. In getStaticPaths return { paths: [], fallback: 'blocking' }.
Prefetch queries with createServerSideHelpers in getServerSideProps
In getServerSideProps, create helpers with createServerSideHelpers passing router, ctx: {}, and transformer: superjson. Call helpers.procedureName.prefetch() to prefetch data. Return { props: { trpcState: helpers.dehydrate(), ...otherProps } }.
Configure SSR response caching with responseMeta
In createTRPCNext config, add responseMeta function that receives opts object containing clientErrors. Return an object with status and headers. Use cache-control header with s-maxage and stale-while-revalidate. Example: responseMeta(opts) { if (opts.clientErrors.length) return { status: opts.clientErrors[0].data?.httpStatus ?? 500 }; return { headers: new Headers([['cache-control', 's-maxage=1, stale-while-revalidate=86400']]) }; }
Common mistake: using ssr: true without understanding implications
Enabling ssr: true imports react-dom and runs ssrPrepass on every request, rendering the component tree repeatedly until no queries are fetching. This adds latency and server load. For better control, keep ssr: false (the default) and use createServerSideHelpers in getServerSideProps or getStaticProps to selectively prefetch only the queries you need.
SSR prepass renders multiple times by design
The SSR prepass loop re-renders the component tree repeatedly until all queries resolve. This is by design but causes performance issues with expensive renders. Keep SSR-rendered pages lightweight, or switch to selective prefetching with server-side helpers.
Mixing App Router and Pages Router patterns causes errors
App Router uses fetchRequestHandler, createTRPCOptionsProxy, and @trpc/tanstack-react-query. Pages Router uses createNextApiHandler, createTRPCNext, and @trpc/next/@trpc/react-query. Applying App Router patterns (like HydrationBoundary or prefetchQuery) in Pages Router, or vice versa, produces non-functional code.
Must return trpcState from getStaticProps/getServerSideProps
When using createServerSideHelpers, you must return trpcState: helpers.dehydrate() in props. Without this, the prefetched data is lost and queries re-fetch on the client. Correct usage: return { props: { trpcState: helpers.dehydrate(), id } };
Next.js tRPC FormData example setup
The Next.js tRPC FormData example can be set up by running: npx create-next-app --example https://github.com/trpc/trpc --example-path examples/next-formdata trpc-formdata, then cd trpc-formdata, npm i, and npm run dev.