Skip to main content

Usage with Next.js


If you're using tRPC in a new project, consider using one of the example projects as a starting point or for reference: tRPC Example Projects

tRPC and Next.js are a match made in heaven! Next.js makes it easy for you to build your client and server together in one codebase. This makes it easy to share types between them.

tRPC includes dedicated tools to make the Next.js developer experience as seamless as possible.

Recommended file structure#

Recommended but not enforced file structure. This is what you get when starting from the examples.

.โ”œโ”€โ”€ prisma # <-- if prisma is addedโ”‚   โ””โ”€โ”€ [..]โ”œโ”€โ”€ srcโ”‚   โ”œโ”€โ”€ pagesโ”‚   โ”‚   โ”œโ”€โ”€ _app.tsx # <-- add `withTRPC()`-HOC hereโ”‚   โ”‚   โ”œโ”€โ”€ apiโ”‚   โ”‚   โ”‚   โ””โ”€โ”€ trpcโ”‚   โ”‚   โ”‚       โ””โ”€โ”€ [trpc].ts # <-- tRPC HTTP handlerโ”‚   โ”‚   โ””โ”€โ”€ [..]โ”‚   โ”œโ”€โ”€ serverโ”‚   โ”‚   โ”œโ”€โ”€ routersโ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ app.ts   # <-- main app routerโ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ post.ts  # <-- sub routersโ”‚   โ”‚   โ”‚   โ””โ”€โ”€ [..]โ”‚   โ”‚   โ”œโ”€โ”€ context.ts      # <-- create app contextโ”‚   โ”‚   โ””โ”€โ”€ createRouter.ts # <-- router helperโ”‚   โ””โ”€โ”€ utilsโ”‚       โ””โ”€โ”€ trpc.ts  # <-- your typesafe tRPC hooksโ””โ”€โ”€ [..]

Add tRPC to existing Next.js project#

1. Install deps#

yarn add @trpc/client @trpc/server @trpc/react @trpc/next zod react-query
  • React Query: @trpc/react provides a thin wrapper over react-query. It is required as a peer dependency.
  • Zod: most examples use Zod for input validation, though it isn't required. You can use a validation library of your choice (Yup, Superstruct, io-ts, etc). In fact, any object containing a parse, create or validateSync method will work.

2. Create a tRPC router#

Implement your tRPC router in ./pages/api/trpc/[trpc].ts. If you need to split your router into several subrouters, implement them in a top-level server directory in your project root, then import them into ./pages/api/trpc/[trpc].ts and merge them into a single root appRouter.

View sample router
import * as trpc from '@trpc/server';import * as trpcNext from '@trpc/server/adapters/next';import { z } from 'zod';
const appRouter = trpc.router().query('hello', {  input: z    .object({      text: z.string().nullish(),    })    .nullish(),  resolve({ input }) {    return {      greeting: `hello ${input?.text ?? 'world'}`,    };  },});
// export type definition of APIexport type AppRouter = typeof appRouter;
// export API handlerexport default trpcNext.createNextApiHandler({  router: appRouter,  createContext: () => null,});

3. Create tRPC hooks#

Create a set of strongly-typed hooks using your API's type signature.

// utils/trpc.tsimport { createReactQueryHooks } from '@trpc/react';import type { AppRouter } from '../pages/api/trpc/[trpc]';
export const trpc = createReactQueryHooks<AppRouter>();// => { useQuery: ..., useMutation: ...}

4. Configure _app.tsx#

The createReactQueryHooks function expects certain parameters to be passed via the Context API. To set these parameters, create a custom _app.tsx using the withTRPC higher-order component:

import { withTRPC } from '@trpc/next';import { AppType } from 'next/dist/shared/lib/utils';
const MyApp: AppType = ({ Component, pageProps }) => {  return <Component {...pageProps} />;};
export default withTRPC<AppRouter>({  config({ ctx }) {    /**     * If you want to use SSR, you need to use the server's full URL     * @link     */    const url = process.env.VERCEL_URL      ? `https://${process.env.VERCEL_URL}/api/trpc`      : 'http://localhost:3000/api/trpc';
    return {      url,      /**       * @link       */      // queryClientConfig: { defaultOptions: { queries: { staleTime: 60 } } },    };  },  /**   * @link   */  ssr: true,})(MyApp);

5. Make API requests#

import { trpc } from '../utils/trpc';
const IndexPage = () => {  const hello = trpc.useQuery(['hello', { text: 'client' }]);  if (! {    return <div>Loading...</div>;  }  return (    <div>      <p>{}</p>    </div>  );};
export default IndexPage;

withTRPC() options#


The config-argument is a function that returns an object that configures the tRPC and React Query clients. This function has a ctx input that gives you access to the Next.js req object, among other things. The returned value can contain the following properties:

  • Exactly one of these are required:

    • url your API URL.
    • links to customize the flow of data between tRPC Client and the tRPC-server. Read more.
  • Optional:

    • queryClientConfig: a configuration object for the React Query QueryClient used internally by the tRPC React hooks: QueryClient docs
    • headers: an object or a function that returns an object of outgoing tRPC requests
    • transformer: a transformer applied to outgoing payloads. Read more about Data Transformers
    • fetch: customize the implementation of fetch used by tRPC internally
    • AbortController: customize the implementation of AbortController used by tRPC internally

ssr-boolean (default: false)#

Whether tRPC should await queries when server-side rendering a page. Defaults to false.


Ability to set request headers and HTTP status when server-side rendering.


export default withTRPC<AppRouter>({  config({ ctx }) { /* [...] */ },  ssr: true,  responseMeta({ clientErrors, ctx }) {    if (clientErrors.length) {      // propagate first http error from API calls      return {        status: clientErrors[0].data?.httpStatus ?? 500,      };    }    // cache full page for 1 day + revalidate once every second    const ONE_DAY_IN_SECONDS = 60 * 60 * 24;    return {      'Cache-Control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,    };  },})(MyApp);

Next steps#

Refer to the @trpc/react docs for additional information on executing Queries and Mutations inside your components.