tRPC!!!

tRPC, short for TypeScript RPC, is a modern development tool designed for building typesafe APIs easily. It leverages TypeScript to enable end-to-end type safety from the client to the server. You can see it in action with the GIF below.

trpc demo from trpc.io landing page

The number one reason I would recommend tRPC is speed! You save tremendous amount of time when your client and server share the same types. You break things quickly, and fix them right away because you know what code broke it. Debugging is a whole lot faster! And the great part is, it is really easy to setup.

You don't need to learn or configure any complex new technology to get your server running. You just need to know how to write functions. The learning curve is so flat that even junior developers can easily onboard, start writing functions and building features end-to-end with a basic understanding of typescript and your business usecase.

Setup and Installation

tRPC's simplicity and type safety have made it really popular amongst developers looking to streamline their API development process. For detailed guidance, you should always check the official tRPC documentation which is more comprehensive and has resources and examples. But here's a quick sneak peak.

import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { z } from 'zod';
import { db } from './db.js';
import { publicProcedure, router } from './trpc.js';

const appRouter = router({
  userList: publicProcedure.query(async () => {
    // Retrieve users from a datasource, this is an imaginary database
    const users = await db.user.findMany();
    //    ^?
    return users;
  }),
  userById: publicProcedure.input(z.string()).query(async (opts) => {
    const { input } = opts;
    //      ^?
    // Retrieve the user with the given ID
    const user = await db.user.findById(input);
    return user;
  }),
  userCreate: publicProcedure
    .input(z.object({ name: z.string() }))
    .mutation(async (opts) => {
      const { input } = opts;
      //      ^?
      // Create a new user in the database
      const user = await db.user.create(input);
      //    ^?
      return user;
    }),
});

// Export type router type signature,
// NOT the router itself.
export type AppRouter = typeof appRouter;

const server = createHTTPServer({
  router: appRouter,
});

server.listen(3000);

This is a short version. But it will do the trick. Depending on your client framework, all you then need to do is call your appRouter on the client side and access each of those procedures.

More reasons why you should be using TRPC in your next project

  1. End-to-End Type Safety: tRPC ensures type safety across the entire stack, from the server to the client, significantly reducing the risk of runtime errors related to data types.

  2. No Code Generation: Unlike some other tools, tRPC doesn't require code generation for types. Types are inferred automatically, simplifying the development process.

  3. Simplified Data Fetching: tRPC allows developers to call server-side functions directly from the client, streamlining data fetching without the need for REST or GraphQL APIs.

  4. Enhanced Developer Experience: With TypeScript integration, tRPC offers a better developer experience, including features like auto-completion and refactoring capabilities.

  5. Reduced Boilerplate: By eliminating the need for manual type definitions and API routes, tRPC cuts down on boilerplate code, making the codebase cleaner and more maintainable.

  6. Flexible and Lightweight: tRPC is adaptable to various use cases and works seamlessly with existing tools and frameworks in the TypeScript ecosystem. It's also lightweight, adding minimal overhead to projects.

If these don't convince you, just reach out to me. We can have a full blown debate about it :)