tRPC vs GraphQL: How to choose the best option for your next project
GraphQL has become the successor to REST as the standard for building APIs. It wraps a query around a request, allowing particular information to be fetched, instead of REST's one-size-fits-all approach. This leads to significant performance benefits.
Despite its popularity, many companies experience serious problems implementing and growing with this technology. It's complex and takes a lot of time to develop an API that works effectively. GraphQL can often be poorly implemented if developers aren't experienced, so this can pose a problem, too.
Fortunately, there is another option - tRPC.
tRPC is a more lightweight alternative to GraphQL that can speed up development and improve performance drastically. In this article, we'll discuss what each of these technologies are, and provide some advice to help you choose the best one for your application. Let's get started!
What is GraphQL?
Graph Query Language (or GraphQL) is a query language that fetches data from an endpoint and returns it to the client. GraphQL focuses on giving the client exactly the data it needs, and nothing extra, and it does this by wrapping requests around queries so they describe specific requirements for what information needs to be returned. As a result, the client is only returned the exact pieces of data it needs, as opposed to REST which returns all the data from an endpoint.
For REST APIs, data types do not need to be typed out as part of the property. In GraphQL, the type of data does need to be typed in properties, and this can greatly reduce the frequency of bugs on the frontend. It does mean you will be making a heavy investment in spending time defining types, though.
How GraphQL Works
GraphQL is used to create schemas that describe all the data the client can possibly request. These schemas use a sort of nested, recursive structure and are organised into types and fields.
Types make sure the client can only request data that the server is capable of delivering. It also means more helpful and easy-to-understand errors can be provided to developers. GraphQL supports a range of types, including Int, Float, String, Boolean and ID. To define a type, include the field name with a colon and the type of data the object can contain. For example:
{name: String}
This would define the name field's type as a string. Generally, defining a type will be much more complex than this, and will involve objects and lists, but at the basic level, this is how you do it.
Some of the biggest problems with GraphQL are caused by developers using it for the wrong purposes. GraphQL is not designed to talk with your database, so your client side shouldn't be querying your database for information, and neither should your server. It's designed for the client to query the server for information, and for the most part, this is the only time you should use this language.
Tying your API to the database can create a range of problems, especially when it comes to scaling your app. When you connect your frontend directly to the database with GraphQL, they need to have similar architectures so they can communicate effectively. In many cases, you'll be limited to the changes you can make on the frontend because of the fact that you'll need to complement them on the backend, too.
Benefits of Using GraphQL
GraphQL is quickly becoming one of the most popular ways to build more complex APIs, and for good reason. It has a lot of benefits to consider when choosing what technology to use in your application.
1. Works without TypeScript
One of the biggest benefits of GraphQL is that it can define types without requiring TypeScript. If you have backend developers who don't want to use JavaScript or a frontend team that prefers frameworks like Flutter (which doesn't support TypeScript), you will still be able to use GraphQL for your application.
2. Highly scalable
For backend development teams who are heavily focused on scaling their side of an application, GraphQL can be a great solution. It provides a set of rules that are all defined and agreed upon in one schema, which can then be improved on gradually as needed. It's easy to start relatively small, and slowly add to the schema as your API becomes increasingly more complex and intricate.
3. Resource efficient
Unlike REST, GraphQL can be used to fetch just the information required, rather than the entire endpoint payload. This is a big deal for mobile apps that need to be mindful of their bandwidth requirements for users with slower connections or on limited data plans.
Downsides of Using GraphQL
While it is a fantastic, powerful language, GraphQL is not for everyone. Here are some of its downsides.
1. Hard to get right
While it's great for larger teams that have GraphQL experts to make sure everything gets done the right way, smaller teams may find it challenging to build schemas that work well for their needs. A lot of smaller teams see large tech companies like Pinterest, FaceBook and GitHub using GraphQL and assume that they should too, but this is not necessarily the case. GraphQL is really easy to mess up because you're essentially adding a bunch of extra steps to something like REST, often without having the skills and knowledge to do so effectively.
2. Messy version management
After a schema is generated, it's assigned a version number. When the frontend sends a request to the server, it uses the most recent version of the schema to return information. There are a lot of problems that can arise from this if you're running an old version of the application. Essentially, the frontend is trying to pull data from the server using a schema built for an entirely different version of the app. It just doesn't work.
GraphQL is a huge step up from REST, and making the switch is often well worthwhile. However, it can be overkill for a lot of projects. Developers are always looking for ways to make complex processes more simple, and this was essentially the mission statement behind tRPC.
GraphQL was a huge step up from REST, and it's honestly pretty awesome, but can be overkill for a lot of projects. The development community are always looking for ways of simplifying a complex art. This was essentially the mission statement behind tRPC, which could arguably be described as the next step in simplified API technology"
What is tRPC?
tRPC stands for TypeScript Remote Procedure Call, and is the most simple and lightweight library for remotely calling backend functions on the client side. It aims to provide developers with the experience of TypeScript inference to make communication between the backend and frontend more productive.
This does mean you will require TypeScript on both your backend and frontend, but if you already have your application set up like this, tRPC is easy to implement. Unlike GraphQL, tRPC is not schema, but a protocol (or 'method') for exposing backend functions to the frontend. It simplifies your API by making the backend and frontend work more closely together to ultimately result in a more lightweight and better-performing application.
How tRPC Works
tRPC does not use schemas or code generation to build APIs. Since it's designed to be an easier, more efficient choice for developers, creating tRPC APIs is relatively simple. The frontend uses procedures to remotely call backend data. Procedures are composable, which means they are made up of components. There are two types of procedures - queries and mutations:
- Queries: A query is a request sent from the client to fetch data from the backend.
- Mutations: A mutation can then create, update or delete data on the backend.
When working with tRPC, you'll usually find it much easier to use a monorepo, and the library heavily encourages you to do so. Modern application architecture has moved towards using multiple repos to separate the backend, frontend and other key areas. A monorepo is just one repository that contains all of an application's code. tRPC's type definitions are generated from your TypeScript code itself, so if you choose not to use a monorepo, you'll probably find that a range of problems start to occur when it comes to working with different versions.
Benefits of Using tRPC
Although tRPC is a lot less popular than GraphQL, for many developers, it's a much better choice. Here are some of its biggest benefits.
1. Simple and lightweight
tRPC is a very light library that you can use to build complete, working APIs without any schemas and code generation. When the client requests information from the server, it only calls the types rather than the actual code itself, which involves a lot less processing. Additionally, tRPC uses TypeScript, which is a statically typed language. Type definitions are checked during compiling, rather than at runtime, increasing the speed of your applications.
2. Encourages monorepos
With tRPC, it's generally much easier to use a monorepo. While it may feel like a disadvantage to have this limitation, it's actually highly beneficial for things like version control and git history. If you're running an old version of your app, your frontend will be able to query the relevant version of your backend. Without a monorepo, when running an old version of your frontend, the app would query the latest version, which may not be compatible with the version you're currently running.
3. Fast development
tRPC is the quickest and easiest way to develop an API. TypeScript allows tRPC to use type inference, which means the type of data is automatically detected (or inferred). Type inference helps development move much quicker, especially in the early stages. tRPC can also comfortably integrate with most IDEs to further streamline development.
Downsides of Using tRPC
As with anything, tRPC is not perfect and is not suitable for everyone. It has strong limitations, which are often downsides to the technology.
1. Requires TypeScript
tRPC is completely centred around TypeScript and it can be annoying to be forced to use it, especially on a small project or some kind of utility where it would not normally be necessary. If you decide to start using tRPC in a non-TypeScript application, you're going to have to implement that before you can actually get started with tRPC.
Should I use tRPC or GraphQL?
Often, you won't start off a project using one or the other. You'll develop a set of specific needs in your application that lead to one of them becoming the better option.
Use GraphQL if:
- You want to separate your backend and frontend (or work from two repos). GraphQL creates a standard for passing information between backend and frontend developers working on the same project. If for some reason they don't communicate effectively or if they have different, it can ensure they adhere to a common standard. Ultimately this reduces the risk of introducing bugs and issues, improves the quality of code, and speeds up development.
- You're scaling your backend and need a clear set of rules for your API. If your backend teams are focused on scaling their side of the application, it's important to create a schema that everyone agrees on so that the two sides of the app can work together as effectively as possible. GraphQL is a great solution for this.
- The application has increasingly more complex and intricate requirements. Whether it's to scale your application's architecture, optimise its design, or essentially any other reason, if you need to build more complex capabilities into your app, GraphQL is almost certainly the best way to do it.
- TypeScript isn't an option for you. If your backend or frontend developers prefer different technologies to JavaScript, or if TypeScript isn't an option for some reason, GraphQL is a good choice, as you get some of the benefits of strongly typed data without having to use on TypeScriptt.
Use tRPC if:
- You want to bring the backend and frontend closer together. If you have a small to medium sized team of developers who need to start working more closely together to effectively build your application, tRPC is the way to achieve this. Since it's a 'method' rather than a schema, things are less clearly defined, but this does mean backend and frontend teams will work much more efficiently.
- You don't have complex needs. If you don't foresee the need for using other (non-JavaScript) languages in your app, and if your architecture and requirements are relatively straightforward, you should be considering tRPC. It requires JavaScript, but is generally the best way to eliminate unnecessary complexity.
- Your app needs to be more lightweight and simple. tRPC eliminates all the unnecessary fluff so that you can build a reliable and simple API that calls backend data on the frontend effectively. It is a lot quicker and easier to implement, so development times will be drastically reduced compared to a solution like GraphQL.
- You're building a Next.js project. tRPC helps connect Next's back and frontend. A lot of people forget that Next.js actually fits the definition of a backend framework, since it runs on a server. Adding tRPC to a Next.js stack is a great way to simplify your technology choices for a full-stack application.
Wrapping up
GraphQL is a powerful step up from REST, but it adds more complexity to a project that is often necessary. tRPC is a great solution for calling backend functions on the frontend that leverages a lot of GraphQL's benefits, with significantly less complexity.
If your next project needs a frontend and backend but you don't want to separate them, then you might want to consider using tRPC!
If we haven't answered your questions, or you think we've missing the point completely, feel free to leave a comment below and we'll get back you in a few working days.