Define Routers
To begin building your tRPC-based API, you'll first need to define your router. Once you've mastered the fundamentals, you can customize your routers for more advanced use cases.
Initialize tRPC
You should initialize tRPC exactly once per application. Multiple instances of tRPC will cause issues.
server/trpc.tsts
import {initTRPC } from '@trpc/server';// You can use any variable name you like.// We use t to keep things simple.constt =initTRPC .create ();export constrouter =t .router ;export constmiddleware =t .middleware ;export constpublicProcedure =t .procedure ;
server/trpc.tsts
import {initTRPC } from '@trpc/server';// You can use any variable name you like.// We use t to keep things simple.constt =initTRPC .create ();export constrouter =t .router ;export constmiddleware =t .middleware ;export constpublicProcedure =t .procedure ;
You'll notice we are exporting certain methods of the t
variable here rather than t
itself. This is to establish a certain set of procedures that we will use idiomatically in our codebase.
Defining a router
Next, let's define a router with a procedure to use in our application. We are now exposing an API "endpoint."
server/_app.tsts
import * astrpc from '@trpc/server';import {publicProcedure ,router } from './trpc';constappRouter =router ({greeting :publicProcedure .query (() => 'hello tRPC v10!'),});// Export only the type of a router!// This prevents us from importing server code on the client.export typeAppRouter = typeofappRouter ;
server/_app.tsts
import * astrpc from '@trpc/server';import {publicProcedure ,router } from './trpc';constappRouter =router ({greeting :publicProcedure .query (() => 'hello tRPC v10!'),});// Export only the type of a router!// This prevents us from importing server code on the client.export typeAppRouter = typeofappRouter ;
Advanced usage
When initializing your router, tRPC allows you to:
- setup request contexts
- assign metadata to procedures
- format and handle errors
- transform data as needed
- customize the runtime configuration
You can use method chaining to customize your t
-object on initialization. For example:
ts
const t = initTRPC().context<Context>().meta<Meta>().create({/* [...] */});
ts
const t = initTRPC().context<Context>().meta<Meta>().create({/* [...] */});
Runtime Configuration
ts
export interface RuntimeConfig<TTypes extends RootConfigTypes> {/*** Use a data transformer* @link https://trpc.io/docs/data-transformers*/transformer: TTypes['transformer'];/*** Use custom error formatting* @link https://trpc.io/docs/error-formatting*/errorFormatter: ErrorFormatter<TTypes['ctx'], any>;/*** Allow `@trpc/server` to run in non-server environments* @warning **Use with caution**, this should likely mainly be used within testing.* @default false*/allowOutsideOfServer: boolean;/*** Is this a server environment?* @warning **Use with caution**, this should likely mainly be used within testing.* @default typeof window === 'undefined' || 'Deno' in window || process.env.NODE_ENV === 'test'*/isServer: boolean;/*** Is this development?* Will be used to decide if the API should return stack traces* @default process.env.NODE_ENV !== 'production'*/isDev: boolean;}
ts
export interface RuntimeConfig<TTypes extends RootConfigTypes> {/*** Use a data transformer* @link https://trpc.io/docs/data-transformers*/transformer: TTypes['transformer'];/*** Use custom error formatting* @link https://trpc.io/docs/error-formatting*/errorFormatter: ErrorFormatter<TTypes['ctx'], any>;/*** Allow `@trpc/server` to run in non-server environments* @warning **Use with caution**, this should likely mainly be used within testing.* @default false*/allowOutsideOfServer: boolean;/*** Is this a server environment?* @warning **Use with caution**, this should likely mainly be used within testing.* @default typeof window === 'undefined' || 'Deno' in window || process.env.NODE_ENV === 'test'*/isServer: boolean;/*** Is this development?* Will be used to decide if the API should return stack traces* @default process.env.NODE_ENV !== 'production'*/isDev: boolean;}