How tRPC Works for Type Safety in Next.js
š§ **Overview**: tRPC enables full-stack type safety in Next.js applications by letting you define your API procedures and types in one place and automatically inferring them on the client. No more manual API typings!
š **Folder Structure** (Recommended for tRPC in Next.js):
1src/
2āāā server/
3ā āāā trpc/
4ā ā āāā routers/
5ā ā ā āāā example.ts
6ā ā ā āāā _app.ts
7ā ā āāā utils.ts
8ā ā āāā context.ts
9ā āāā index.ts
10āāā pages/
11ā āāā api/
12ā āāā trpc/[trpc].ts
13āāā utils/
14 āāā trpc.ts
1ļøā£ **Install tRPC dependencies:**
1npm install @trpc/server @trpc/client @trpc/react-query @tanstack/react-query zod
2ļøā£ **Server-Side Setup** (`src/server/trpc`):
1// utils.ts
2import { initTRPC } from "@trpc/server";
3
4const t = initTRPC.create();
5export const router = t.router;
6export const publicProcedure = t.procedure;
7
8// context.ts
9export const createContext = async () => ({});
10export type Context = Awaited<ReturnType<typeof createContext>>;
11
12// routers/example.ts
13import { publicProcedure, router } from "../utils";
14import { z } from "zod";
15
16export const exampleRouter = router({
17 hello: publicProcedure
18 .input(z.object({ name: z.string() }))
19 .query(({ input }) => {
20 return { greeting: `Hello, ${input.name}!` };
21 }),
22});
23
24// routers/_app.ts
25import { router } from "../utils";
26import { exampleRouter } from "./example";
27
28export const appRouter = router({
29 example: exampleRouter,
30});
31export type AppRouter = typeof appRouter;
3ļøā£ **API Handler** (`pages/api/trpc/[trpc].ts`):
1import { createNextApiHandler } from "@trpc/server/adapters/next";
2import { appRouter } from "@/server/trpc/routers/_app";
3import { createContext } from "@/server/trpc/context";
4
5export default createNextApiHandler({
6 router: appRouter,
7 createContext,
8});
4ļøā£ **Client-Side Setup** (`src/utils/trpc.ts`):
1import { createTRPCReact } from "@trpc/react-query";
2import type { AppRouter } from "@/server/trpc/routers/_app";
3
4export const trpc = createTRPCReact<AppRouter>();
5ļøā£ **Using tRPC in a React Component**:
1import { trpc } from "@/utils/trpc";
2
3export default function HomePage() {
4 const helloQuery = trpc.example.hello.useQuery({ name: "Ravikant" });
5
6 if (helloQuery.isLoading) return <p>Loading...</p>;
7 if (helloQuery.error) return <p>Error: {helloQuery.error.message}</p>;
8
9 return <p>{helloQuery.data?.greeting}</p>;
10}
šÆ With this setup, your API input and output types are automatically inferred on the client from the server definitions ā ensuring type safety across the stack without manual syncing.