tRPC with Next.JS
Disclaimer
This is from my experience in many personal projects and use in production software.
Although this framework is best used with Next.JS it can also be used with many different front/back-end frameworks. This implementation will be using the T3 stack(https://create.t3.gg/en/introduction) which eliminates much of the boilerplate and configuration you would have to do otherwise.
For more details see the official docs:
What is tRPC?
tRPC, standing for TypeScript Remote Procedure Call, serves as a robust alternative to conventional REST API endpoints, offering a method to consume APIs in a fully type-safe manner via procedure calls. It caters predominantly to full-stack TypeScript developers, capitalizing on type-safety to ensure accuracy and efficiency.
Unlike other frameworks, tRPC requires the server and the client to be coupled within the same repository. This architecture lends itself particularly well to full-stack frameworks such as Next.js. Acting as an intermediary layer between the client and server, tRPC manages data transfer and transformation without discarding types, thus maintaining the integrity of the data.
One of the primary benefits of tRPC is its emphasis on static typing and intelligent code completion (IntelliSense) across the full stack. This can significantly boost developer productivity, decrease the frequency of bugs in production, and extend the advantages of TypeScript and static types from the server to client-side components.
Above all, tRPC is highly performant and engineered to impact load times minimally, ensuring your web applications remain responsive and efficient. It exemplifies a blend of performance, productivity, and reliability for full-stack development.
How to use tRPC?
Configuration
To simplify the tRPC configuration we can use the T3 stack which can provide us with all of the Next.js tooling we want for most use cases.
To initialize a new project using this we will use
npm create t3-app@latest
While you have the freedom to choose any optional packages for your project, tRPC is a mandatory if you would like to utilize the T3 stack configuration. After the package initialization is completed, all the necessary file scaffolding and boilerplate will be automatically set up. No further configuration is required to start using tRPC with Next.js.
Server
When it comes to leveraging tRPC, my preferred approach is to first define the server actions or endpoints prior to any data transfer to the client side. In the realm of tRPC, these are known as ‘routes’ and ‘procedures’ — essentially functions that are made accessible to the client and callable by users. Procedures usually fall into two categories: ‘query’ and ‘mutation’.
Query
This is primarily used to fetch data and not to alter it. Query is essentially a thin wrapper around react-query so it is helpful to understand these concepts deeply before diving into the slightly different way tRPC handles this. By ‘fetch and not alter’ I mean it is traditionally used for the R in CRUD operations (Create, Read, Update, Delete).
Mutation
This is used when data is going to be altered. This means it is the CUD in CRUD operations, so Creating, Updating, or Deleting. It also works very similar to the useMutation hook in react. So it is good to look at the official react documentation on how that hook works.
Router
A router is essentially just an API endpoint that contains all of the procedures we will be calling from the client. The naming of these routers are arbitrary and there is a lot of freedom in how you can organize these. In the T3 stack there is src -> server -> routers -> example.ts. This ‘example.ts’ file is the default router used in the T3 stack and the procedures can already be called in the client. You can define any new procedures you would like to use or even create your own router. All you have to do to create your own is create a new file in the routers folder, copy the template in example.ts, remove the procedures and rename, then list this in the root.ts folder
Here is a real world example that I created for a project using Axios and a rapid API
https://github.com/AustinHood7/t3-moon-data/blob/main/src/server/api/routers/example.ts
Client
Now that the hard part is out of the way we can now use our client to call the procedures we created in the router. This is done very simply using the format of
const data = api.route.procedure.useQuery();
or in applied terms
const moonData = api.example.getMoonData.useQuery();
and now we can use the data fetched from the server just as we would with a traditional REST API. The benefits may not seem immediate but we can use IntelliSense and all of the types that have been defined on the server are transferred to the client.
Overview
Overall the process of creating a fully type-safe application is very simple with tRPC.
- Create a procedure on the server to get or mutate the data
- Call the procedure from the client
Some important notes are that you still must conform to TypeScript rules, like having schemas and linking these with Zod schemas. This process can be a bit confusing if you are not familiar with TypeScript. I will be posting a more in depth tutorial on how to use both of these schemas to fetch data from APIs and storing them within objects.
If this type of content interests you or have any ideas on anything I can help with, please consider following my page.