---
name: nextjs-pages-router
description: Set up tRPC in Next.js Pages Router with createNextApiHandler, createTRPCNext (config, transformer, ssr, ssrPrepass, responseMeta) and the withTRPC HOC over @trpc/react-query hooks. Prefetch selected pages with createServerSideHelpers in getServerSideProps or getStaticProps and return trpcState, or SSR every query with ssr true, forwarding request headers.
requires:
  - server-setup
  - client-setup
sources:
  - www/v11/docs/client/nextjs/pages-router/setup.md
  - www/v11/docs/client/nextjs/pages-router/server-side-helpers.md
  - www/v11/docs/client/nextjs.md
  - www/v11/docs/client/nextjs/pages-router/ssr.md
  - www/v11/docs/client/nextjs/pages-router/ssg.md
  - www/v11/docs/server/adapters/nextjs.md
  - www/v11/docs/client/nextjs/pages-router/aborting-procedure-calls.md
  - www/v11/docs/client/react/useQuery.md
  - www/v11/docs/client/react/useMutation.md
  - www/v11/docs/client/react/useUtils.md
metadata:
  type: framework
  library: trpc
  library_version: 11.23.0
---

<!-- Generated from www/v11/docs/client/nextjs/pages-router/setup.md by www/build/skills.ts. Edit the docs instead. -->

# Set up with Next.js Pages Router (deprecated)

From https://trpc.io/docs/client/nextjs/pages-router/setup

> [!WARNING] Deprecated
> The Next.js Pages Router integration (`@trpc/next`) is deprecated in favor of the [TanStack React Query integration](https://trpc.io/docs/client/tanstack-react-query) (`@trpc/tanstack-react-query`). To use it with Next.js, follow [Set up with Next.js App Router](https://trpc.io/docs/client/nextjs/app-router-setup).


> [!WARNING] Caution
> This guide is for the **Next.js Pages Router**. If you are using the **Next.js App Router**, see the [App Router setup guide](https://trpc.io/docs/client/nextjs/app-router-setup) instead.


## Recommended file structure

We recommend a file structure like this one, although it is not enforced by tRPC. This is what you'll see in [our examples](https://trpc.io/docs/example-apps). The rest of this page will take you through the process of adding tRPC in to this structure.

```graphql
.
├── 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
│   │   └── trpc.ts      # <-- procedure helpers
│   └── utils
│       └── trpc.ts  # <-- your typesafe tRPC hooks
└── [..]
```

## Add tRPC to existing Next.js project

### 1. Install deps

```bash
npm install @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@latest zod
```

The Next.js integration is actually a combination of our [classic React Query Integration](https://trpc.io/docs/client/react) (deprecated: it only gets bug fixes, and will be removed in the next major version of tRPC in favor of the [TanStack React Query integration](https://trpc.io/docs/client/tanstack-react-query)) and some Next.js-specific integrations.

### 2. Enable strict mode

If you want to use Zod for input validation, make sure you have enabled strict mode in your `tsconfig.json`:

```diff title="tsconfig.json"
"compilerOptions": {
+   "strict": true
}
```

If strict mode is too harsh, you'll at least want to enable `strictNullChecks`:

```diff title="tsconfig.json"
"compilerOptions": {
+   "strictNullChecks": true
}
```

### 3. Create a tRPC router

Initialize your tRPC backend in `src/server/trpc.ts` using the `initTRPC` function, and create your first router. We're going to make a simple "hello world" router and procedure here - but for deeper information on creating your tRPC API you should refer to:

- the [Quickstart guide](https://trpc.io/docs/quickstart) and [Backend usage docs](https://trpc.io/docs/server/overview) for tRPC information
- the [Next.js Adapter docs](https://trpc.io/docs/server/adapters/nextjs) for mounting tRPC within your Next.js server.

<details>
<summary>View sample backend</summary>

```ts no-check title="server/trpc.ts"
import { initTRPC } from '@trpc/server';

// Avoid exporting the entire t-object
// since it's not very descriptive.
// For instance, the use of a t variable
// is common in i18n libraries.
const t = initTRPC.create();

// Base router and procedure helpers
export const router = t.router;
export const procedure = t.procedure;
```

<br />

```ts no-check title="server/routers/_app.ts"
import { z } from 'zod';
import { procedure, router } from '../trpc';

export const appRouter = router({
  hello: procedure
    .input(
      z.object({
        text: z.string(),
      }),
    )
    .query((opts) => {
      return {
        greeting: `hello ${opts.input.text}`,
      };
    }),
});

// export type definition of API
export type AppRouter = typeof appRouter;
```

<br />

```ts no-check title="pages/api/trpc/[trpc].ts"
import * as trpcNext from '@trpc/server/adapters/next';
import { appRouter } from '../../../server/routers/_app';

// export API handler
// @link https://trpc.io/docs/server/adapters
export default trpcNext.createNextApiHandler({
  router: appRouter,
  createContext: () => ({}),
});
```

</details>

> [!NOTE]
> The backend above is using the [recommended file structure](https://trpc.io/docs/client/nextjs/pages-router/setup#recommended-file-structure), but you can keep it simple and put everything in [an API handler directly](https://github.com/trpc/trpc/blob/main/examples/next-minimal-starter/src/pages/api/trpc/%5Btrpc%5D.ts) if you prefer.


### 4. Create tRPC hooks

Use the `createTRPCNext` function to create a set of strongly-typed hooks from your API's type signature.

```tsx no-check title="utils/trpc.ts"
import { httpBatchLink } from '@trpc/client';
import { createTRPCNext } from '@trpc/next';
import type { AppRouter } from '../server/routers/_app';

function getBaseUrl() {
  if (typeof window !== 'undefined')
    // browser should use relative path
    return '';

  if (process.env.VERCEL_URL)
    // reference for vercel.com
    return `https://${process.env.VERCEL_URL}`;

  if (process.env.RENDER_INTERNAL_HOSTNAME)
    // reference for render.com
    return `http://${process.env.RENDER_INTERNAL_HOSTNAME}:${process.env.PORT}`;

  // assume localhost
  return `http://localhost:${process.env.PORT ?? 3000}`;
}

export const trpc = createTRPCNext<AppRouter>({
  config(config) {
    return {
      links: [
        httpBatchLink({
          /**
           * If you want to use SSR, you need to use the server's full URL
           * @see https://trpc.io/docs/client/nextjs/pages-router/ssr
           **/
          url: `${getBaseUrl()}/api/trpc`,

          // You can pass any HTTP headers you wish here
          async headers() {
            return {
              // authorization: getAuthCookie(),
            };
          },
        }),
      ],
    };
  },
  /**
   * @see https://trpc.io/docs/client/nextjs/pages-router/ssr
   **/
  ssr: false,
});
```

> [!NOTE]
> `createTRPCNext` does not work with the tRPC-v9 interop mode. If you are migrating from v9 using interop, you should continue using [the old way of initializing tRPC](https://trpc.io/docs/v9/nextjs#4-create-trpc-hooks).


### 5. Configure `_app.tsx`

Wrap your root app page in the `trpc.withTRPC` HOC, similar to this:

```tsx no-check title="pages/_app.tsx"
import type { AppType } from 'next/app';
import { trpc } from '../utils/trpc';

const MyApp: AppType = ({ Component, pageProps }) => {
  return <Component {...pageProps} />;
};

export default trpc.withTRPC(MyApp);
```

### 6. Make an API request

You're all set!

You can now use the React hooks you have just created to invoke your API. For more detail see the [React Query Integration](https://trpc.io/docs/client/react/setup)

```tsx no-check title="pages/index.tsx"
import { trpc } from '../utils/trpc';

export default function IndexPage() {
  const hello = trpc.hello.useQuery({ text: 'client' });
  if (!hello.data) {
    return <div>Loading...</div>;
  }
  return (
    <div>
      <p>{hello.data.greeting}</p>
    </div>
  );
}
```

## `createTRPCNext()` options

### `config`-callback

The `config`-argument is a function that returns an object that configures the tRPC and React Query clients. This function receives an object with an optional `ctx` property (of type `NextPageContext`) that gives you access to the Next.js `req` object during server-side rendering. The returned value can contain the following properties:

- **Required**:
- `links` to customize the flow of data between tRPC Client and the tRPC Server. [Read more](https://trpc.io/docs/client/links).
- Optional:
- `queryClientConfig`: a configuration object for the React Query `QueryClient` used internally by the tRPC React hooks: [QueryClient docs](https://tanstack.com/query/v5/docs/reference/QueryClient)
- `queryClient`: a React Query [QueryClient instance](https://tanstack.com/query/v5/docs/reference/QueryClient)
  - **Note:** You can only provide either a `queryClient` or a `queryClientConfig`.
- `abortOnUnmount`: determines if in-flight requests will be cancelled on component unmount. This defaults to `false`.

### `transformer`

If your router uses a [data transformer](https://trpc.io/docs/server/data-transformers), pass it here as well as to your links. tRPC uses it to read the `trpcState` that [SSR](https://trpc.io/docs/client/nextjs/pages-router/ssr), [SSG](https://trpc.io/docs/client/nextjs/pages-router/ssg) and the [server-side helpers](https://trpc.io/docs/client/nextjs/pages-router/server-side-helpers) send to the page.

### `overrides`: (default: `undefined`)

Configure [overrides for React Query's hooks](https://trpc.io/docs/client/react/useUtils#invalidate-full-cache-on-every-mutation).

### `ssr`-boolean (default: `false`)

Whether tRPC should await queries when server-side rendering a page. Defaults to `false`. Enabling it requires the `ssrPrepass` option, imported from `@trpc/next/ssrPrepass`, and you can pass a function of the request instead of `true`. See [SSR](https://trpc.io/docs/client/nextjs/pages-router/ssr).

### `responseMeta`-callback

Ability to set response headers and HTTP status when server-side rendering, so it requires `ssr`. It receives the request's `ctx` and the `clientErrors` of the queries that failed. Return `headers` as a plain object: a `Headers` instance is ignored here.

#### Example

```tsx no-check title="utils/trpc.ts"
import { createTRPCNext } from '@trpc/next';
import { ssrPrepass } from '@trpc/next/ssrPrepass';
import type { AppRouter } from '../server/routers/_app';

export const trpc = createTRPCNext<AppRouter>({
  config(config) {
    return {
      links: [
        /* [...] */
      ],
    };
  },
  ssr: true,
  ssrPrepass,
  responseMeta(opts) {
    const error = opts.clientErrors[0];
    if (error) {
      // propagate the HTTP status of the first failed query
      return { status: error.data?.httpStatus ?? 500 };
    }
    return {
      headers: { 'cache-control': 's-maxage=1, stale-while-revalidate=86400' },
    };
  },
});
```

## Common mistakes

- **Turning on `ssr: true` without weighing the cost.** It adds a `getInitialProps` to your app, which turns off Next.js' Automatic Static Optimization and [doesn't mix well with `getServerSideProps`](https://trpc.io/docs/client/nextjs/pages-router/ssr). It also renders the page repeatedly until no query is fetching, so every query delays the response. To prefetch only some pages, keep `ssr: false` and use the [server-side helpers](https://trpc.io/docs/client/nextjs/pages-router/server-side-helpers) in `getServerSideProps` or `getStaticProps`.
- **Not forwarding the request's headers during SSR.** The server-side render calls your API without the user's cookies unless the link's `headers()` passes on `ctx.req.headers`, and it needs an absolute URL. See [SSR](https://trpc.io/docs/client/nextjs/pages-router/ssr).
- **Using Suspense with `ssr: true`.** If a query fails while rendering on the server, the whole page fails, even inside an `<ErrorBoundary />`.
- **Returning the dehydrated state under another key.** `withTRPC` only reads `pageProps.trpcState`, so return `{ props: { trpcState: helpers.dehydrate() } }`. Otherwise the client fetches every query again.
- **Mixing in App Router setup.** `createTRPCNext` and `withTRPC` are for the Pages Router. In the App Router, follow the [App Router setup](https://trpc.io/docs/client/nextjs/app-router-setup) instead.

## Next steps

Browse the rest of the docs to learn more about things like [authorization](https://trpc.io/docs/server/authorization), [middlewares](https://trpc.io/docs/server/middlewares), and [error handling](https://trpc.io/docs/server/error-handling).

You can also find information about [queries](https://trpc.io/docs/client/react/useQuery) and [mutations](https://trpc.io/docs/client/react/useMutation) now that you're using `@trpc/react-query`.

## Server-Side Helpers

From https://trpc.io/docs/client/nextjs/pages-router/server-side-helpers

> [!WARNING] Deprecated
> The Next.js Pages Router integration (`@trpc/next`) is deprecated in favor of the [TanStack React Query integration](https://trpc.io/docs/client/tanstack-react-query) (`@trpc/tanstack-react-query`). To use it with Next.js, follow [Set up with Next.js App Router](https://trpc.io/docs/client/nextjs/app-router-setup).


The server-side helpers provide you with a set of helper functions that you can use to prefetch queries on the server. This is useful for SSG, but also for SSR if you opt not to use `ssr: true`.

Prefetching via the server-side helpers allows populating the query cache on the server, which means that these queries do not have to fetch on the client initially.

### There are 2 ways to use the server-side helpers.

#### 1. Internal router

This method is used when you have direct access to your tRPC router, e.g., when developing a monolithic Next.js application.

Using the helpers makes tRPC call your procedures directly on the server, without an HTTP request, similar to [server-side calls](https://trpc.io/docs/server/server-side-calls).
That also means that you don't have the request and response at hand like you usually do. Make sure you're instantiating the server-side helpers with a context without `req` & `res`, which are typically filled via the context creation. We recommend the concept of ["inner" and "outer" context](https://trpc.io/docs/server/context) in that scenario.

```ts no-check
import { createServerSideHelpers } from '@trpc/react-query/server';
import { createContext } from './server/context';
import { appRouter } from './server/routers/_app';
import superjson from 'superjson';

const helpers = createServerSideHelpers({
  router: appRouter,
  ctx: await createContext(),
  transformer: superjson,
});
```

#### 2. External router

This method is used when you don't have direct access to your tRPC router, e.g., when developing a Next.js application and a standalone API hosted separately.

```ts no-check
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import { createServerSideHelpers } from '@trpc/react-query/server';
import type { AppRouter } from './server/router';
import superjson from 'superjson';

const proxyClient = createTRPCClient<AppRouter>({
  links: [
    httpBatchLink({
      url: 'http://localhost:3000/api/trpc',
    }),
  ],
});

const helpers = createServerSideHelpers({
  client: proxyClient,
});
```

### Helpers usage

The server-side helpers methods return an object that mirrors your router structure, with all of your routers as keys. However, rather than `useQuery` and `useMutation`, you get `prefetch`, `fetch`, `prefetchInfinite`, and `fetchInfinite` functions.

The primary difference between `prefetch` and `fetch` is that `fetch` acts much like a normal function call, returning the result of the query, whereas `prefetch` does not return the result and never throws - if you need that behavior, use `fetch` instead. Instead, `prefetch` will add the query to the cache, which you then dehydrate and send to the client.

```ts no-check
// In getServerSideProps / getStaticProps:
const props = {
  // very important - use `trpcState` as the key
  trpcState: helpers.dehydrate(),
};
```

The rule of thumb is `prefetch` for queries that you know you'll need on the client, and `fetch` for queries that you want to use the result of on the server.

The functions are all wrappers around react-query functions. Please check out [their docs](https://tanstack.com/query/v5/docs/framework/react/overview) to learn more about them in detail.

> [!NOTE] Info
> For a full example, see our [E2E SSG test example](https://github.com/trpc/trpc/tree/main/examples/.test/ssg)


### Next.js Example

```tsx no-check title="pages/posts/[id].tsx"
import { createServerSideHelpers } from '@trpc/react-query/server';
import { appRouter } from './server/routers/_app';
import { trpc } from './utils/trpc';
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
import superjson from 'superjson';

export async function getServerSideProps(
  context: GetServerSidePropsContext<{ id: string }>,
) {
  const helpers = createServerSideHelpers({
    router: appRouter,
    ctx: {},
    transformer: superjson,
  });
  const id = context.params?.id as string;

  /*
   * Prefetching the `post.byId` query.
   * `prefetch` does not return the result and never throws - if you need that behavior, use `fetch` instead.
   */
  await helpers.post.byId.prefetch({ id });

  // Make sure to return { props: { trpcState: helpers.dehydrate() } }
  return {
    props: {
      trpcState: helpers.dehydrate(),
      id,
    },
  };
}

export default function PostViewPage(
  props: InferGetServerSidePropsType<typeof getServerSideProps>,
) {
  const { id } = props;
  const postQuery = trpc.post.byId.useQuery({ id });
  if (postQuery.status !== 'success') {
    // won't happen since the query has been prefetched
    return <>Loading...</>;
  }
  const { data } = postQuery;
  return (
    <>
      <h1>{data.title}</h1>
      <em>Created {data.createdAt.toLocaleDateString()}</em>
      <p>{data.text}</p>
      <h2>Raw data:</h2>
      <pre>{JSON.stringify(data, null, 4)}</pre>
    </>
  );
}
```

## Choosing between App Router and Pages Router

|                     | App Router                                    | Pages Router                                        |
| ------------------- | --------------------------------------------- | --------------------------------------------------- |
| **Recommended for** | New projects                                  | Existing Pages Router projects                      |
| **Data fetching**   | Server Components, `prefetchQuery`            | `getServerSideProps`, `getStaticProps`, SSR via HOC |
| **Server adapter**  | [Fetch adapter](https://trpc.io/docs/server/adapters/fetch)  | [Next.js adapter](https://trpc.io/docs/server/adapters/nextjs)     |
| **Client package**  | `@trpc/tanstack-react-query`                  | `@trpc/next` + `@trpc/react-query`                  |
| **Provider setup**  | Manual `QueryClientProvider` + `TRPCProvider` | Automatic via `withTRPC()` HOC                      |

> [!TIP]
> If you're starting a new project, use the App Router setup with `@trpc/tanstack-react-query`. The Pages Router integration (`@trpc/next`) is deprecated in favor of the TanStack React Query integration.

From https://trpc.io/docs/client/nextjs#choosing-between-app-router-and-pages-router

## References

- [Server-Side Rendering](references/client-nextjs-pages-router-ssr.md): Render every tRPC query on the server with ssr: true and ssrPrepass, forward request headers, and cache SSR responses with responseMeta
- [Static Site Generation](references/client-nextjs-pages-router-ssg.md): Prefetch tRPC queries in getStaticProps with the server-side helpers and stop the client from refetching them
- [Next.js Adapter](references/server-adapters-nextjs.md): Serve tRPC from a Next.js API route with createNextApiHandler, or from an App Router route handler with fetchRequestHandler
- [Aborting Procedure Calls](references/client-nextjs-pages-router-aborting-procedure-calls.md): Cancel in-flight requests when a component unmounts with abortOnUnmount, globally or per request
- [useQuery()](references/client-react-useQuery.md): Fetch data with the classic trpc.procedure.useQuery() hook, its tRPC-specific options and streaming
- [useMutation()](references/client-react-useMutation.md): Call mutations with the classic trpc.procedure.useMutation() hook
- [useUtils](references/client-react-useUtils.md): Invalidate, refetch, prefetch and update cached query data with the classic trpc.useUtils() helpers

## Related skills

- `server-setup` (https://trpc.io/docs/server/overview): `npx @tanstack/intent@latest load @trpc/server#server-setup`
- `client-setup` (https://trpc.io/docs/client/vanilla/setup): `npx @tanstack/intent@latest load @trpc/client#client-setup`
