DEV Community

Cover image for Stop manually setting up tRPC in Next.js — use this CLI instead
Dhavalkurkutiya
Dhavalkurkutiya

Posted on

Stop manually setting up tRPC in Next.js — use this CLI instead

Stop manually setting up tRPC in Next.js — use this CLI instead

Every time I start a new Next.js project with tRPC, I do the same thing.

Open docs. Copy files. Install packages. Forget to wrap layout.tsx. Get the QueryClient error. Fix it. Repeat next project.

I got tired of it. So I built a CLI.

npx create-trpc-setup
Enter fullscreen mode Exit fullscreen mode

The Problem

Setting up tRPC v11 with Next.js App Router is not hard — but it's tedious. Every project needs:

  • Install @trpc/server, @trpc/client, @trpc/tanstack-react-query, @tanstack/react-query, zod, server-only
  • Create trpc/init.ts with context and procedures
  • Create trpc/query-client.ts with SSR-safe QueryClient
  • Create trpc/client.tsx with TRPCReactProvider
  • Create trpc/server.tsx with HydrateClient and prefetch
  • Create app/api/trpc/[trpc]/route.ts
  • Manually update layout.tsx to wrap <body> with TRPCReactProvider

Miss any step → error. Every. Single. Project.


The Solution

npx create-trpc-setup
Enter fullscreen mode Exit fullscreen mode

Run this inside any existing Next.js project. Everything happens automatically.

What gets auto-detected:

  • Package manager — npm, pnpm, yarn, or bun
  • Path alias — reads tsconfig.json for @/*, ~/*, or any custom alias
  • Auth provider — detects Clerk or NextAuth, configures context automatically
  • Folder structure — src/ or root layout

Files Generated

trpc/
├── init.ts              ← context, baseProcedure, protectedProcedure, Zod error formatter
├── query-client.ts      ← SSR-safe QueryClient
├── client.tsx           ← TRPCReactProvider + useTRPC hook
├── server.tsx           ← prefetch, HydrateClient
└── routers/
    └── _app.ts          ← starter router with health + greet (Zod validation)

app/api/trpc/[trpc]/
└── route.ts             ← API handler with real headers + dev error logging

app/trpc-status/         ← styled test page (delete after confirming ✅)
Enter fullscreen mode Exit fullscreen mode

layout.tsx — auto-patched

Before:

<body>
  {children}
  <Toaster />
</body>
Enter fullscreen mode Exit fullscreen mode

After:

<body>
  <TRPCReactProvider>
    {children}
    <Toaster />
  </TRPCReactProvider>
</body>
Enter fullscreen mode Exit fullscreen mode

No backup files. No extra clutter. Just the import added + body wrapped.


Why Not create-t3-app?

create-t3-app is great — but it only works for new projects.

create-trpc-setup works with projects you've already started.

Feature create-t3-app create-trpc-setup
New projects
Existing projects
Auto-patches layout.tsx
Clerk / NextAuth detection
tsconfig path alias detection
tRPC v11 + RSC ready

Using tRPC After Setup

Server Component — prefetch data:

// app/page.tsx
import { HydrateClient, prefetch, trpc } from "@/trpc/server";
import { MyClient } from "./my-client";

export default function Page() {
  prefetch(trpc.greet.queryOptions({ name: "World" }));
  return (
    <HydrateClient>
      <MyClient />
    </HydrateClient>
  );
}
Enter fullscreen mode Exit fullscreen mode

Client Component — use data:

// my-client.tsx
"use client";
import { useSuspenseQuery } from "@tanstack/react-query";
import { useTRPC } from "@/trpc/client";

export function MyClient() {
  const trpc = useTRPC();
  const { data } = useSuspenseQuery(trpc.greet.queryOptions({ name: "World" }));
  return <div>{data.message}</div>;
}
Enter fullscreen mode Exit fullscreen mode

protectedProcedure — Already Included

The generated init.ts includes a protectedProcedure that automatically throws UNAUTHORIZED:

export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
  if (!ctx.userId) {
    throw new TRPCError({ code: "UNAUTHORIZED", message: "Sign in required" });
  }
  return next({ ctx: { ...ctx, userId: ctx.userId } });
});
Enter fullscreen mode Exit fullscreen mode

Use it directly in any router:

getProfile: protectedProcedure.query(({ ctx }) => {
  return { userId: ctx.userId }; // guaranteed non-null ✅
}),
Enter fullscreen mode Exit fullscreen mode

Zod Error Formatter — Also Included

Clean field-level errors on the client:

error?.data?.zodError?.fieldErrors?.title // ["Title is required"]
Enter fullscreen mode Exit fullscreen mode

Try It

npx create-trpc-setup
Enter fullscreen mode Exit fullscreen mode

If this saved you time, drop a ⭐ on GitHub — it helps others find it!


Top comments (0)