Define Routers
To begin building your tRPC-based API, you'll first need to define your router. You can customize your routers for more advanced use cases once you've learned the basics.
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;}