Quickstart

tip

We highly encourage you to check out the Example Apps to get a feel of tRPC and getting up & running as seamless as possible.

Installation

⚠️ Requirements: tRPC requires TypeScript > 4.1 as it relies on Template Literal Types.

npm install @trpc/server

For implementing tRPC endpoints and routers. Install in your server codebase.

npm install @trpc/client

For making typesafe API calls from your client. Install in your client codebase.

npm install @trpc/react

For generating a powerful set of React hooks for querying your tRPC API. Recommended for non-Next.js React projects. Powered by react-query.

npm install @trpc/next

A set of utilies for integrating tRPC with Next.js.

Installation Snippets

npm:

  1. npm install @trpc/server @trpc/client @trpc/react @trpc/next

yarn:

  1. yarn add @trpc/server @trpc/client @trpc/react @trpc/next

Defining a router

Let’s walk through the steps of building a typesafe API with tRPC. To start, this API will only contain two endpoints:

  1. getUser(id: string) => { id: string; name: string; }
  2. createUser(data: {name:string}) => { id: string; name: string; }

Create a router instance

First we define a router somewhere in our server codebase:

  1. // server/index.ts
  2. import * as trpc from '@trpc/server';
  3. const appRouter = trpc.router();
  4. // only export *type signature* of router!
  5. // to avoid accidentally importing your API
  6. // into client-side code
  7. export type AppRouter = typeof appRouter;

Add a query endpoint

Use the .query() method to add a query endpoint to the router. Arguments:

.query(name: string, params: QueryParams)

  • name: string: The name of this endpoint
  • params.input: Optional. This should be a function that validates/casts the input of this endpoint and either returns a strongly typed value (if valid) or throws an error (if invalid). Alternatively you can pass a Zod, Superstruct or Yup schema.
  • params.resolve: This is the actual implementation of the endpoint. It’s a function with a single req argument. The validated input is passed into req.input and the context is in req.ctx (more about context later!)
  1. // server/index.ts
  2. import * as trpc from '@trpc/server';
  3. const appRouter = trpc.router().query('getUser', {
  4. input: (val: unknown) => {
  5. if (typeof val === 'string') return val;
  6. throw new Error(`Invalid input: ${typeof val}`);
  7. },
  8. async resolve(req) {
  9. req.input; // string
  10. return { id: req.input, name: 'Bilbo' };
  11. },
  12. });
  13. export type AppRouter = typeof appRouter;

Add a mutation endpoint

Similarly to GraphQL, tRPC makes a distinction between query and mutation endpoints. Let’s add a createUser mutation:

  1. createUser(payload: {name: string}) => {id: string; name: string};
  1. // server/index.ts
  2. import * as trpc from '@trpc/server';
  3. import { z } from 'zod';
  4. const appRouter = trpc
  5. .router()
  6. .query('getUser', {
  7. input: (val: unknown) => {
  8. if (typeof val === 'string') return val;
  9. throw new Error(`Invalid input: ${typeof val}`);
  10. },
  11. async resolve(req) {
  12. req.input; // string
  13. return { id: req.input, name: 'Bilbo' };
  14. },
  15. })
  16. .mutation('createUser', {
  17. // validate input with Zod
  18. input: z.object({ name: z.string().min(5) }),
  19. async resolve(req) {
  20. // use your ORM of choice
  21. return await UserModel.create({
  22. data: req.input,
  23. });
  24. },
  25. });
  26. export type AppRouter = typeof appRouter;

Next steps

tRPC includes more sophisticated client-side tooling designed for React projects generally and Next.js specifically. Read the appropriate guide next: