How to Level Up Your Full-Stack Game with tRPC and Next.js

Published on Feb 11, 2025

3 min read

🧠 How to Level Up Your Full-Stack Game with tRPC and Next.js

🔗

Full-stack development in 2025 is all about speed, safety, and simplicity. And if you’re tired of writing API schemas, DTOs, and constantly syncing types between your frontend and backend — say hello to tRPC.

In this post, we’ll break down how tRPC + Next.js gives you superpowers for building type-safe, full-stack apps without writing a single line of API boilerplate.


🚀 What Is tRPC?

🔗

tRPC (short for TypeScript Remote Procedure Call) lets you create fully typesafe APIs without needing a REST or GraphQL layer. Your frontend talks to the backend directly through function calls.

You define your procedures once on the server — and call them from the client as if they were local functions, all with full TypeScript support.


⚙️ How It Works in Next.js

🔗

tRPC integrates perfectly with Next.js App Router or Pages Router, and works with React Server Components too.

Here’s the general flow:

  1. Define procedures in a router on the server
  2. Export the router and set up a tRPC server handler (API route or middleware)
  3. Use createTRPCReact() to access procedures from the client

🔧 Example Setup (App Router)

🔗

1. Create your backend router

🔗
1// server/api/trpc.ts
2import { initTRPC } from '@trpc/server';
3
4const t = initTRPC.create();
5export const appRouter = t.router({
6 hello: t.procedure.query(() => 'Hello from tRPC!'),
7});
8
9export type AppRouter = typeof appRouter;

2. Create the tRPC server handler

🔗
1// app/api/trpc/[trpc]/route.ts
2import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
3import { appRouter } from '@/server/api/trpc';
4
5export const dynamic = 'force-dynamic';
6
7export async function GET(req: Request) {
8 return fetchRequestHandler({
9 req,
10 endpoint: '/api/trpc',
11 router: appRouter,
12 createContext: () => ({}),
13 });
14}

3. Use it on the client

🔗
1// app/page.tsx
2'use client';
3
4import { trpc } from '@/utils/trpc';
5
6export default function HomePage() {
7 const hello = trpc.hello.useQuery();
8
9 return <div>{hello.data ?? 'Loading...'}</div>;
10}

🛠 Why Use tRPC?

🔗

End-to-end type safety

No schema duplication
Developer experience is 10/10
Built-in React Query support
Flexible + framework-agnostic core

“If TypeScript is your love language, tRPC is your soulmate.”


🔍 When Not to Use It?

🔗
  • If your app needs a public API, REST or GraphQL may be better
  • If your team isn’t TypeScript-savvy, the learning curve might be steep
  • If you’re doing microservices with non-TypeScript services, tRPC won’t help there

📦 Bonus: Add Zod for Input Validation

🔗

tRPC works great with Zod to validate inputs:

1import { z } from 'zod';
2
3const appRouter = t.router({
4 greet: t.procedure
5 .input(z.object({ name: z.string() }))
6 .query(({ input }) => `Hello, ${input.name}`),
7});

🌍 Final Thoughts

🔗

tRPC isn’t just a tool — it’s a philosophy: “Don’t repeat yourself. Especially not types.”

With tRPC and Next.js, you’re building APIs by not building APIs — just calling strongly typed procedures, backed by full inference and validation.

Ready to level up your stack? Give tRPC a spin and never look back.


📚 Resources

🔗

Got questions or tips about tRPC?

Hit me up on Twitter/X or email me!


Copyright ©  2024-2025 🧡 Amiya Panigrahi 💚 · All Rights Reserved.