Set up a tRPC Client
On this page
1. Install the tRPC Client library
Use your preferred package manager to install the @trpc/client library, and also install @trpc/server which contains some required types.
pnpm add @trpc/server @trpc/clientnpm install @trpc/server @trpc/clientyarn add @trpc/server @trpc/clientbun add @trpc/server @trpc/client2. Import your App Router
Import your AppRouter type into the client application. This type holds the shape of your entire API.
utils/trpc.ts
import type { type AppRouter = Router<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
post: BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
byId: QueryProcedure<{
input: {
id: string;
};
output: {
id: string;
title: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>;
}>> & DecorateCreateRouterOptions<{
post: BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
byId: QueryProcedure<{
input: {
id: string;
};
output: {
id: string;
title: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>;
}>
AppRouter } from '../server/router';3. Initialize the tRPC client
Create a tRPC client with the createTRPCClient method, and add a links array with a terminating link pointing at your API. To learn more about tRPC links, click here.
client.ts
import { function createTRPCClient<TRouter extends AnyRouter>(opts: CreateTRPCClientOptions<TRouter>): TRPCClient<TRouter>createTRPCClient, function httpBatchLink<TRouter extends AnyRouter>(opts: HTTPBatchLinkOptions<TRouter["_def"]["_config"]["$types"]>): TRPCLink<TRouter>httpBatchLink } from '@trpc/client';
import type { type AppRouter = Router<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>> & DecorateCreateRouterOptions<{}>
AppRouter } from './server';
const const client: TRPCClient<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>>
client = createTRPCClient<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>>(opts: CreateTRPCClientOptions<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>>): TRPCClient<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<...>>>
createTRPCClient<type AppRouter = Router<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>> & DecorateCreateRouterOptions<{}>
AppRouter>({
links: TRPCLink<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>>[]
links: [
httpBatchLink<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>>(opts: HTTPBatchLinkOptions<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}>): TRPCLink<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>>
httpBatchLink({
url: string | URLurl: 'http://localhost:3000/trpc',
// You can pass any HTTP headers you wish here
async headers?: HTTPHeaders | ((opts: {
opList: NonEmptyArray<Operation>;
}) => HTTPHeaders | Promise<HTTPHeaders>) | undefined
headers() {
return {
authorization: stringauthorization: function getAuthCookie(): stringgetAuthCookie(),
};
},
}),
],
});4. Use the tRPC Client
Under the hood this creates a typed JavaScript Proxy which allows you to interact with your tRPC API in a fully type-safe way:
client.ts
const const bilbo: {
id: string;
name: string;
}
bilbo = await const client: TRPCClient<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: string;
output: {
id: string;
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: {
name: string;
id: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>>
client.getUser: {
query: Resolver<{
input: string;
output: {
id: string;
name: string;
};
errorShape: DefaultErrorShape;
transformer: false;
}>;
}
getUser.query: (input: string, opts?: TRPCProcedureOptions) => TRPCTaggedPromise<{
id: string;
name: string;
}, DefaultErrorShape>
query('id_bilbo');
// => { id: 'id_bilbo', name: 'Bilbo' };
const const frodo: {
name: string;
id: string;
}
frodo = await const client: TRPCClient<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: string;
output: {
id: string;
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: {
name: string;
id: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>>
client.createUser: {
mutate: Resolver<{
input: {
name: string;
};
output: {
name: string;
id: string;
};
errorShape: DefaultErrorShape;
transformer: false;
}>;
}
createUser.mutate: (input: {
name: string;
}, opts?: TRPCProcedureOptions) => TRPCTaggedPromise<{
name: string;
id: string;
}, DefaultErrorShape>
mutate({ name: stringname: 'Frodo' });
// => { id: 'id_frodo', name: 'Frodo' };You're all set!
Common mistakes
- Leaving out the
AppRoutertype parameter.createTRPCClient({ links })without<AppRouter>compiles, but none of your procedures are typed. If theAppRouterimport doesn't resolve (often a monorepo path ortsconfigissue), fix the import rather than reaching forcreateTRPCClient<any>. - Importing the router value instead of its type.
import { appRouter } from '../server/router'pulls your server code into the client bundle. Exporttype AppRouter = typeof appRouterfrom the server and import it withimport type. - Passing
transformertocreateTRPCClient. The transformer belongs on each terminating link (httpBatchLink,httpLink,wsLink, ...), and TypeScript rejects it on the client itself. See Data Transformers. - Using
createTRPCProxyClient. It's the v10 name, kept as a deprecated alias ofcreateTRPCClient. - Calling procedures like REST endpoints. Procedures are addressed by their dot-separated path, for example
GET /trpc/post.byId?input=..., not/trpc/post/1. Call them through the client, or see the HTTP RPC Specification for the wire format. - A JSON parse error like
Unexpected token '<'. The request reached something that answered with an HTML page, usually a 404, so the link'surldoesn't match where your adapter serves tRPC (check the/trpcprefix).