Usage

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

.
├── server
│   ├── api
│   │   └── trpc
│   │       └── [trpc].ts  # <-- tRPC HTTP handler
│   │   └── [..]
│   ├── trpc
│   │   ├── routers
│   │   │   ├── index.ts  # <-- main app router
│   │   │   ├── todo.ts  # <-- sub routers
│   │   │   └── [..]
│   │   ├── context.ts   # <-- create app context
│   │   └── trpc.ts      # <-- procedure helpers
├── plugins
│   ├── client.ts  # <-- tRPC Client as a plugin
└── [..]

1. Create a tRPC router

Initialize your tRPC backend using the initTRPC function and create your first router.

server/trpc/trpc.ts
import { initTRPC } from '@trpc/server'// Avoid exporting the entire t-object since it's not very// descriptive and can be confusing to newcomers used to t// meaning translation in i18n libraries.const t = initTRPC.create()// Base router and procedure helpersexport const router = t.routerexport const publicProcedure = t.procedure
server/trpc/routers/index.ts
import { z } from 'zod'import { publicProcedure, router } from '../trpc'export const appRouter = router({  hello: publicProcedure    .input(      z.object({        text: z.string().nullish(),      }),    )    .query(({ input }) => {      return {        greeting: `hello ${input?.text ?? 'world'}`,      }    }),})// export type definition of APIexport type AppRouter = typeof appRouter
server/api/trpc/[trpc].ts
import { createNuxtApiHandler } from 'trpc-nuxt'import { appRouter } from '@/server/trpc/routers'// export API handlerexport default createNuxtApiHandler({  router: appRouter,  createContext: () => ({}),})
If you need to split your router into several subrouters, you can implement them in the server/trpc/routers directory and import and merge them to a single root appRouter.

2. Create tRPC client plugin

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

plugins/client.ts
import { httpBatchLink } from '@trpc/client'import { createTRPCNuxtProxyClient } from 'trpc-nuxt/client'import type { AppRouter } from '@/server/trpc/routers'export default defineNuxtPlugin(() => {  const client = createTRPCNuxtProxyClient<AppRouter>({    links: [      httpBatchLink({        /**         * If you want to use SSR, you need to use the server's full URL         * @link https://trpc.io/docs/ssr         **/        url: 'http://localhost:3000/api/trpc',      }),    ],  })  return {    provide: {      client,    },  }})

3. Make API requests

pages/index.vue
<script setup lang="ts">const { $client } = useNuxtApp()// query and mutate uses useAsyncData under the hoodconst { data, pending, error } = await $client.hello.query({ text: 'client' })</script><template>  <div v-if="pending">    Loading...  </div>  <div v-else-if="error?.data?.code">    Error: {{ error.data.code }}  </div>  <div v-else>    <p>{{ hello.data?.greeting }}</p>  </div></template>