Next.js 13 + tRPC: A Match Made in Heaven
Dive into the powerful synergy between Next.js 13 and tRPC in this comprehensive guide.
Discover how this dynamic duo empowers web developers to create blazing-fast and highly interactive applications. From leveraging Next.js 13’s cutting-edge features to harnessing tRPC's facilities that provide a type-safe way to build APIs.
Without wasting any more of your time, lets get straight into it!
Table of Contents
- Setup Next.js 13 Project Environment
- Dependencies Installation
- Creating a tRPC Server
- Configuring tRPC for Client-Side and Server-Side
- Server tRPC Example
- Client tRPC Example
Setup Next.js 13 Project Environment
To setup a Next.js project, please check out the instructions here. The installation process generally consists of running the following command in the terminal.
npx create-next-app@latest
Dependencies Installation
Open a terminal within your project directory, and execute one of the following commands to get started:
npm install @trpc/client @trpc/server @trpc/react-query @tanstack/react-query zod
yarn add @trpc/client @trpc/server @trpc/react-query @tanstack/react-query zod
pnpm add @trpc/client @trpc/server @trpc/react-query @tanstack/react-query zod
Creating a tRPC Server
- Go into the
src/
folder in your Next.js 13 project — or inside the root of your project if you didn’t select thesrc/
folder option — and create a new folder calledserver
with a file calledtrpc.ts
:
import { initTRPC } from "@trpc/server";
const t = initTRPC.create();
export const router = t.router;
export const publicProcedure = t.procedure;
This is simple boilerplate code to allow you to create API procedures
and routers
in your Next.js 13 backend.
2. Inside the src/server/
directory, create a new file called index.ts
:
import { z } from "zod"
import { publicProcedure, router } from "./trpc"
export const appRouter = router({
getData: publicProcedure.query(async () => {
// Here you would fetch data from a database in a
// real-life application.
console.log("getData")
return "getData"
}),
setData: publicProcedure
.input(z.string())
.mutation(async ({ input }) => {
// Here you would update a database using the
// input string passed into the procedure
console.log(input)
return input
}),
})
// This type will be used as a reference later...
export type AppRouter = typeof appRouter
- We import the
publicProcedure
androuter
functions defined inside thetrpc.ts
file. - Next we create an
appRouter
, which acts as a hub for your APIprocedures
. - Inside the
appRouter
I defined a trivialgetData
andsetData
function for tutorial’s sake. - In the
setData
function, the codeinput(z.string())
ensures the input data is validated usingzod
maximizing endpoint security and developer experience.
3. Go inside the app/
directory, and create a sequence of files and directories as follows: api/trpc/[trpc]/route.ts
.
import { appRouter } from "@/server"
import { fetchRequestHandler } from "@trpc/server/adapters/fetch"
const handler = (req: Request) =>
fetchRequestHandler({
endpoint: "/api/trpc",
req,
router: appRouter,
createContext: () => ({}),
})
export { handler as GET, handler as POST }
This creates an API endpoint that is called when a procedure
is run.
Configuring tRPC for Client-Side and Server-Side
- Inside the
app/
directory, create a folder called_trpc
and with a file calledclient.ts
. This defines a tRPC instance that is usable inside all your Next.js 13 client-components.
import { type AppRouter } from "@/server"
import { createTRPCReact } from "@trpc/react-query"
export const trpc = createTRPCReact<AppRouter>({})
2. Within the same folder, create a file called serverClient.ts
to define a tRPC instance that works for all server-side components.
import { appRouter } from "@/server"
import { httpBatchLink } from "@trpc/client"
export const serverClient = appRouter.createCaller({
links: [
httpBatchLink({
url: "http://localhost:3000/api/trpc",
}),
],
})
NOTE: You will need to change the url http:localhost:3000
when deploying your code to production, In this case, you should conditionally select the url as follows:
import { appRouter } from "@/server"
import { httpBatchLink } from "@trpc/client"
const url =
process.env.NODE_ENV === "production"
? "your-production-url/api/trpc"
: "http://localhost:3000/api/trpc"
export const serverClient = appRouter.createCaller({
links: [
httpBatchLink({ url }),
],
})
Server tRPC Example
Lets run our procedures
that we’ve defined earlier inside a server component! Open up app/page.tsx
and copy the following code:
import { serverClient } from "./_trpc/serverClient"
export default async function page() {
const data = await serverClient.getData()
const dataSet = await serverClient.setData("test-data")
return (
<main>
<div>{data}</div>
<div>{dataSet}</div>
</main>
)
}
Run the application using npm run dev
inside a terminal window, then visit localhost:3000/
; you should see the data within the UI and within the server-side terminal window.
Client tRPC Example
Now lets run the same procedures
inside a client component! Open up app/page.tsx
and copy the following code:
"use client"
import { trpc } from "@/app/_trpc/client"
export default async function page() {
const getData = trpc.getData.useQuery({
// your react-query properties ...
})
const setData = trpc.setData.useMutation({
// your react-query properties ...
})
return (
<main>
<div>{getData.data}</div>
<div>{setData.data}</div>
</main>
)
}
Conclusion:
In both the server-side and client-side examples, you may have noticed that the data returned is 100% type-safe! This is the main reason tRPC is so great!
Your Next.js 13 project workflow should now increase tenfold as the data from external endpoints is 100% validated + type-safe, ready to bring your projects to life.
I hope you’ve enjoyed this article! You now have a fully functional and scalable tRPC backend within your Next.js 13 project!
If you have any questions and concerns, please be sure to let me know, and as always, stay tuned for more! 👍
Level Up Coding
Thanks for being a part of our community! Before you go:
- 👏 Clap for the story and follow the author 👉
- 📰 View more content in the Level Up Coding publication
- 💰 Free coding interview course ⇒ View Course
- 🧠 AI Tools ⇒ View Now
🔔 Follow us: Twitter | LinkedIn | Newsletter
🚀👉 Join the Level Up talent collective and find an amazing job