Skip to content
tRPC

HTTP RPC Specification

On this page

Methods <-> Type mapping

HTTP MethodMappingNotes
GET.query()Input JSON-stringified in query param.
e.g. myQuery?input=${encodeURIComponent(JSON.stringify(input))}
POST.mutation()Input as POST body.
GET.subscription()Subscriptions are supported via Server-sent Events using httpSubscriptionLink, or via WebSockets using wsLink.

Accessing nested procedures

Nested procedures are separated by dots, so a request to byId below would end up being a request to /api/trpc/post.byId.

export const 
const appRouter: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        byId: QueryProcedure<{
            input: string;
            output: void;
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>>
appRouter
=
const router: RouterBuilder
<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        byId: QueryProcedure<{
            input: string;
            output: void;
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}>(_: {
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        byId: QueryProcedure<{
            input: string;
            output: void;
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
    }>>;
}) => BuiltRouter<...>
router
({
post: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    byId: QueryProcedure<{
        input: string;
        output: void;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
post
:
const router: RouterBuilder
<{
    byId: QueryProcedure<{
        input: string;
        output: void;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>(_: {
    byId: QueryProcedure<{
        input: string;
        output: void;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}) => BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    byId: QueryProcedure<{
        input: string;
        output: void;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
router
({
byId: QueryProcedure<{
    input: string;
    output: void;
    meta: object;
    errorShape: DefaultErrorShape;
}>
byId
: const publicProcedure: ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>publicProcedure.ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.input<StringConstructor>(schema: StringConstructor): ProcedureBuilder<object, object, object, string, string, UnsetMarker, UnsetMarker, false, DefaultErrorShape>input(var String: StringConstructorString).
ProcedureBuilder<object, object, object, string, string, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.query<void>(resolver: ProcedureResolver<object, object, object, string, UnsetMarker, void>): QueryProcedure<{
    input: string;
    output: void;
    meta: object;
    errorShape: DefaultErrorShape;
}>
query
(async (opts: ProcedureResolverOptions<object, object, object, string>opts) => {
// [...] }), }), });

Batching

When batching, we combine all parallel procedure calls of the same HTTP method in one request using a data loader.

  • The called procedures' names are combined by a comma (,) in the pathname
  • Input parameters are sent as a query parameter called input which has the shape Record<number, unknown>.
  • We also need to pass batch=1 as a query parameter.
  • If the response has different statuses, we send back 207 Multi-Status (e.g., if one call errored and one succeeded)

Batching Example Request

Given a router like this exposed at /api/trpc:

server/router.ts
export const 
const appRouter: BuiltRouter<{
    ctx: Context;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    postById: QueryProcedure<{
        input: string;
        output: Post | null;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    relatedPosts: QueryProcedure<{
        input: string;
        output: Post[];
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
appRouter
=
const t: TRPCRootObject<Context, object, RuntimeConfigOptions<Context, object>, {
    ctx: Context;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
t
.
TRPCRootObject<Context, object, RuntimeConfigOptions<Context, object>, { ctx: Context; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.router: RouterBuilder
<{
    postById: QueryProcedure<{
        input: string;
        output: Post | null;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    relatedPosts: QueryProcedure<{
        input: string;
        output: Post[];
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>(_: {
    postById: QueryProcedure<{
        input: string;
        output: Post | null;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    relatedPosts: QueryProcedure<{
        input: string;
        output: Post[];
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}) => BuiltRouter<...>
router
({
postById: QueryProcedure<{
    input: string;
    output: Post | null;
    meta: object;
    errorShape: DefaultErrorShape;
}>
postById
:
const t: TRPCRootObject<Context, object, RuntimeConfigOptions<Context, object>, {
    ctx: Context;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
t
.TRPCRootObject<Context, object, RuntimeConfigOptions<Context, object>, { ctx: Context; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.procedure: ProcedureBuilder<Context, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>procedure.ProcedureBuilder<Context, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.input<StringConstructor>(schema: StringConstructor): ProcedureBuilder<Context, object, object, string, string, UnsetMarker, UnsetMarker, false, DefaultErrorShape>input(var String: StringConstructorString).
ProcedureBuilder<Context, object, object, string, string, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.query<Post | null>(resolver: ProcedureResolver<Context, object, object, string, UnsetMarker, Post | null>): QueryProcedure<{
    input: string;
    output: Post | null;
    meta: object;
    errorShape: DefaultErrorShape;
}>
query
(async (opts: ProcedureResolverOptions<Context, object, object, string>opts) => {
const const post: Post | nullpost = await opts: ProcedureResolverOptions<Context, object, object, string>opts.
ProcedureResolverOptions<Context, object, object, string>.ctx: {
    post: {
        findUnique: (opts: {
            where: {
                id: string;
            };
        }) => Promise<Post | null>;
    };
    findRelatedPostsById: (id: string) => Promise<Post[]>;
}
ctx
.
post: {
    findUnique: (opts: {
        where: {
            id: string;
        };
    }) => Promise<Post | null>;
}
post
.
findUnique: (opts: {
    where: {
        id: string;
    };
}) => Promise<Post | null>
findUnique
({
where: {
    id: string;
}
where
: { id: stringid: opts: ProcedureResolverOptions<Context, object, object, string>opts.ProcedureResolverOptions<Context, object, object, string>.input: stringinput },
}); return const post: Post | nullpost; }),
relatedPosts: QueryProcedure<{
    input: string;
    output: Post[];
    meta: object;
    errorShape: DefaultErrorShape;
}>
relatedPosts
:
const t: TRPCRootObject<Context, object, RuntimeConfigOptions<Context, object>, {
    ctx: Context;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
t
.TRPCRootObject<Context, object, RuntimeConfigOptions<Context, object>, { ctx: Context; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.procedure: ProcedureBuilder<Context, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>procedure.ProcedureBuilder<Context, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.input<StringConstructor>(schema: StringConstructor): ProcedureBuilder<Context, object, object, string, string, UnsetMarker, UnsetMarker, false, DefaultErrorShape>input(var String: StringConstructorString).
ProcedureBuilder<Context, object, object, string, string, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.query<Post[]>(resolver: ProcedureResolver<Context, object, object, string, UnsetMarker, Post[]>): QueryProcedure<{
    input: string;
    output: Post[];
    meta: object;
    errorShape: DefaultErrorShape;
}>
query
(async (opts: ProcedureResolverOptions<Context, object, object, string>opts) => {
const const posts: Post[]posts = await opts: ProcedureResolverOptions<Context, object, object, string>opts.
ProcedureResolverOptions<Context, object, object, string>.ctx: {
    post: {
        findUnique: (opts: {
            where: {
                id: string;
            };
        }) => Promise<Post | null>;
    };
    findRelatedPostsById: (id: string) => Promise<Post[]>;
}
ctx
.findRelatedPostsById: (id: string) => Promise<Post[]>findRelatedPostsById(opts: ProcedureResolverOptions<Context, object, object, string>opts.ProcedureResolverOptions<Context, object, object, string>.input: stringinput);
return const posts: Post[]posts; }), });

... And two queries defined like this in a React component:

MyComponent.tsx
export function function MyComponent(): React.JSX.ElementMyComponent() {
  const const post1: anypost1 = const trpc: anytrpc.postById.useQuery('1');
  const const relatedPosts: anyrelatedPosts = const trpc: anytrpc.relatedPosts.useQuery('1');

  return (
    <React.JSX.IntrinsicElements.pre: React.DetailedHTMLProps<React.HTMLAttributes<HTMLPreElement>, HTMLPreElement>pre>
      {var JSON: JSONJSON.JSON.stringify(value: any, replacer?: (number | string)[] | null, space?: string | number): string (+1 overload)stringify(
        {
          post1: anypost1: const post1: anypost1.data ?? null,
          relatedPosts: anyrelatedPosts: const relatedPosts: anyrelatedPosts.data ?? null,
        },
        null,
        4,
      )}
    </React.JSX.IntrinsicElements.pre: React.DetailedHTMLProps<React.HTMLAttributes<HTMLPreElement>, HTMLPreElement>pre>
  );
}

The above would result in exactly 1 HTTP call with this data:

Location propertyValue
pathname/api/trpc/postById,relatedPosts
search?batch=1&input=%7B%220%22%3A%221%22%2C%221%22%3A%221%22%7D *

*) input in the above is the result of:

function encodeURIComponent(uriComponent: string | number | boolean): stringencodeURIComponent(
  var JSON: JSONJSON.JSON.stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string (+1 overload)stringify({
    0: '1', // <-- input for `postById`
    1: '1', // <-- input for `relatedPosts`
  }),
);

Batching Example Response

Example output from server
[
  // result for `postById`
  {
    "result": {
      "data": {
        "id": "1",
        "title": "Hello tRPC",
        "body": "..."
        // ...
      }
    }
  },
  // result for `relatedPosts`
  {
    "result": {
      "data": [
        /* ... */
      ]
    }
  }
]

HTTP Response Specification

In order to have a specification that works regardless of the transport layer we try to conform to JSON-RPC 2.0 where possible.

Successful Response

Example JSON Response
{
  "result": {
    "data": {
      "id": "1",
      "title": "Hello tRPC",
      "body": "..."
    }
  }
}
interface SuccessResponse {
  
SuccessResponse.result: {
    data: TOutput;
}
result
: {
data: anydata: type TOutput = anyTOutput; // output from procedure } }

Error Response

Example JSON Response
[
  {
    "error": {
      "json": {
        "message": "Something went wrong",
        "code": -32600, // JSON-RPC 2.0 code
        "data": {
          // Extra, customizable, meta data
          "code": "INTERNAL_SERVER_ERROR",
          "httpStatus": 500,
          "stack": "...",
          "path": "post.add"
        }
      }
    }
  }
]

  • When possible, we propagate HTTP status codes from the error thrown.
  • If the response has different statuses, we send back 207 Multi-Status (e.g., if one call errored and one succeeded)
  • For more on errors and how to customize them see Error Formatting.

Error Codes <-> HTTP Status

const 
const HTTP_STATUS_CODES: {
    readonly PARSE_ERROR: 400;
    readonly BAD_REQUEST: 400;
    readonly UNAUTHORIZED: 401;
    readonly PAYMENT_REQUIRED: 402;
    readonly FORBIDDEN: 403;
    readonly NOT_FOUND: 404;
    readonly METHOD_NOT_SUPPORTED: 405;
    readonly TIMEOUT: 408;
    readonly CONFLICT: 409;
    readonly PRECONDITION_FAILED: 412;
    readonly PAYLOAD_TOO_LARGE: 413;
    readonly UNSUPPORTED_MEDIA_TYPE: 415;
    readonly UNPROCESSABLE_CONTENT: 422;
    readonly PRECONDITION_REQUIRED: 428;
    readonly TOO_MANY_REQUESTS: 429;
    readonly CLIENT_CLOSED_REQUEST: 499;
    readonly INTERNAL_SERVER_ERROR: 500;
    readonly NOT_IMPLEMENTED: 501;
    readonly BAD_GATEWAY: 502;
    readonly SERVICE_UNAVAILABLE: 503;
    readonly GATEWAY_TIMEOUT: 504;
}
HTTP_STATUS_CODES
= {
type PARSE_ERROR: 400PARSE_ERROR: 400, type BAD_REQUEST: 400BAD_REQUEST: 400, type UNAUTHORIZED: 401UNAUTHORIZED: 401, type PAYMENT_REQUIRED: 402PAYMENT_REQUIRED: 402, type FORBIDDEN: 403FORBIDDEN: 403, type NOT_FOUND: 404NOT_FOUND: 404, type METHOD_NOT_SUPPORTED: 405METHOD_NOT_SUPPORTED: 405, type TIMEOUT: 408TIMEOUT: 408, type CONFLICT: 409CONFLICT: 409, type PRECONDITION_FAILED: 412PRECONDITION_FAILED: 412, type PAYLOAD_TOO_LARGE: 413PAYLOAD_TOO_LARGE: 413, type UNSUPPORTED_MEDIA_TYPE: 415UNSUPPORTED_MEDIA_TYPE: 415, type UNPROCESSABLE_CONTENT: 422UNPROCESSABLE_CONTENT: 422, type PRECONDITION_REQUIRED: 428PRECONDITION_REQUIRED: 428, type TOO_MANY_REQUESTS: 429TOO_MANY_REQUESTS: 429, type CLIENT_CLOSED_REQUEST: 499CLIENT_CLOSED_REQUEST: 499, type INTERNAL_SERVER_ERROR: 500INTERNAL_SERVER_ERROR: 500, type NOT_IMPLEMENTED: 501NOT_IMPLEMENTED: 501, type BAD_GATEWAY: 502BAD_GATEWAY: 502, type SERVICE_UNAVAILABLE: 503SERVICE_UNAVAILABLE: 503, type GATEWAY_TIMEOUT: 504GATEWAY_TIMEOUT: 504, } as
type const = {
    readonly PARSE_ERROR: 400;
    readonly BAD_REQUEST: 400;
    readonly UNAUTHORIZED: 401;
    readonly PAYMENT_REQUIRED: 402;
    readonly FORBIDDEN: 403;
    readonly NOT_FOUND: 404;
    readonly METHOD_NOT_SUPPORTED: 405;
    readonly TIMEOUT: 408;
    readonly CONFLICT: 409;
    readonly PRECONDITION_FAILED: 412;
    readonly PAYLOAD_TOO_LARGE: 413;
    readonly UNSUPPORTED_MEDIA_TYPE: 415;
    readonly UNPROCESSABLE_CONTENT: 422;
    readonly PRECONDITION_REQUIRED: 428;
    readonly TOO_MANY_REQUESTS: 429;
    readonly CLIENT_CLOSED_REQUEST: 499;
    readonly INTERNAL_SERVER_ERROR: 500;
    readonly NOT_IMPLEMENTED: 501;
    readonly BAD_GATEWAY: 502;
    readonly SERVICE_UNAVAILABLE: 503;
    readonly GATEWAY_TIMEOUT: 504;
}
const
;

Error Codes <-> JSON-RPC 2.0 Error Codes

Available codes & JSON-RPC code
/**
 * JSON-RPC 2.0 Error codes
 *
 * `-32000` to `-32099` are reserved for implementation-defined server-errors.
 * For tRPC we're copying the last digits of HTTP 4XX errors.
 */
export const 
const TRPC_ERROR_CODES_BY_KEY: {
    readonly PARSE_ERROR: -32700;
    readonly BAD_REQUEST: -32600;
    readonly INTERNAL_SERVER_ERROR: -32603;
    readonly NOT_IMPLEMENTED: -32603;
    readonly BAD_GATEWAY: -32603;
    readonly SERVICE_UNAVAILABLE: -32603;
    readonly GATEWAY_TIMEOUT: -32603;
    readonly UNAUTHORIZED: -32001;
    readonly PAYMENT_REQUIRED: -32002;
    readonly FORBIDDEN: -32003;
    readonly NOT_FOUND: -32004;
    readonly METHOD_NOT_SUPPORTED: -32005;
    readonly TIMEOUT: -32008;
    readonly CONFLICT: -32009;
    readonly PRECONDITION_FAILED: -32012;
    readonly PAYLOAD_TOO_LARGE: -32013;
    readonly UNSUPPORTED_MEDIA_TYPE: -32015;
    readonly UNPROCESSABLE_CONTENT: -32022;
    readonly PRECONDITION_REQUIRED: -32028;
    readonly TOO_MANY_REQUESTS: -32029;
    readonly CLIENT_CLOSED_REQUEST: -32099;
}
TRPC_ERROR_CODES_BY_KEY
= {
/** * Invalid JSON was received by the server. * An error occurred on the server while parsing the JSON text. */ type PARSE_ERROR: -32700PARSE_ERROR: -32700, /** * The JSON sent is not a valid Request object. */ type BAD_REQUEST: -32600BAD_REQUEST: -32600, // 400 // Internal JSON-RPC error type INTERNAL_SERVER_ERROR: -32603INTERNAL_SERVER_ERROR: -32603, // 500 type NOT_IMPLEMENTED: -32603NOT_IMPLEMENTED: -32603, // 501 type BAD_GATEWAY: -32603BAD_GATEWAY: -32603, // 502 type SERVICE_UNAVAILABLE: -32603SERVICE_UNAVAILABLE: -32603, // 503 type GATEWAY_TIMEOUT: -32603GATEWAY_TIMEOUT: -32603, // 504 // Implementation specific errors type UNAUTHORIZED: -32001UNAUTHORIZED: -32001, // 401 type PAYMENT_REQUIRED: -32002PAYMENT_REQUIRED: -32002, // 402 type FORBIDDEN: -32003FORBIDDEN: -32003, // 403 type NOT_FOUND: -32004NOT_FOUND: -32004, // 404 type METHOD_NOT_SUPPORTED: -32005METHOD_NOT_SUPPORTED: -32005, // 405 type TIMEOUT: -32008TIMEOUT: -32008, // 408 type CONFLICT: -32009CONFLICT: -32009, // 409 type PRECONDITION_FAILED: -32012PRECONDITION_FAILED: -32012, // 412 type PAYLOAD_TOO_LARGE: -32013PAYLOAD_TOO_LARGE: -32013, // 413 type UNSUPPORTED_MEDIA_TYPE: -32015UNSUPPORTED_MEDIA_TYPE: -32015, // 415 type UNPROCESSABLE_CONTENT: -32022UNPROCESSABLE_CONTENT: -32022, // 422 type PRECONDITION_REQUIRED: -32028PRECONDITION_REQUIRED: -32028, // 428 type TOO_MANY_REQUESTS: -32029TOO_MANY_REQUESTS: -32029, // 429 type CLIENT_CLOSED_REQUEST: -32099CLIENT_CLOSED_REQUEST: -32099, // 499 } as
type const = {
    readonly PARSE_ERROR: -32700;
    readonly BAD_REQUEST: -32600;
    readonly INTERNAL_SERVER_ERROR: -32603;
    readonly NOT_IMPLEMENTED: -32603;
    readonly BAD_GATEWAY: -32603;
    readonly SERVICE_UNAVAILABLE: -32603;
    readonly GATEWAY_TIMEOUT: -32603;
    readonly UNAUTHORIZED: -32001;
    readonly PAYMENT_REQUIRED: -32002;
    readonly FORBIDDEN: -32003;
    readonly NOT_FOUND: -32004;
    readonly METHOD_NOT_SUPPORTED: -32005;
    readonly TIMEOUT: -32008;
    readonly CONFLICT: -32009;
    readonly PRECONDITION_FAILED: -32012;
    readonly PAYLOAD_TOO_LARGE: -32013;
    readonly UNSUPPORTED_MEDIA_TYPE: -32015;
    readonly UNPROCESSABLE_CONTENT: -32022;
    readonly PRECONDITION_REQUIRED: -32028;
    readonly TOO_MANY_REQUESTS: -32029;
    readonly CLIENT_CLOSED_REQUEST: -32099;
}
const
;

Overriding the default HTTP method

To override the HTTP method used for queries/mutations, you can use the methodOverride option:

server/httpHandler.ts
// Your server must separately allow the client to override the HTTP method
const const handler: http.RequestListenerhandler = 
createHTTPHandler<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{}>>>(opts: CreateHTTPHandlerOptions<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{}>>>): http.RequestListener
createHTTPHandler
({
BaseHandlerOptions<BuiltRouter<{ ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }, DecorateCreateRouterOptions<{}>>, http.IncomingMessage>.router: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{}>>
router
:
const router: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{}>>
router
,
BaseHandlerOptions<TRouter extends AnyRouter, TRequest>.allowMethodOverride?: boolean | undefinedallowMethodOverride: true, });
client/trpc.ts
import { function createTRPCClient<TRouter extends AnyRouter>(opts: CreateTRPCClientOptions<TRouter>): TRPCClient<TRouter>createTRPCClient, function httpLink<TRouter extends AnyRouter = AnyRouter>(opts: HTTPLinkOptions<TRouter["_def"]["_config"]["$types"]>): TRPCLink<TRouter>httpLink } from '@trpc/client';
import type { 
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{}>> & DecorateCreateRouterOptions<{}>
AppRouter
} from './server';
// The client can then specify which HTTP method to use for all queries/mutations 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
: [
httpLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{}>>>(opts: HTTPLinkOptions<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>): TRPCLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{}>>>
httpLink
({
url: string | URLurl: `http://localhost:3000`, methodOverride?: "POST" | undefinedmethodOverride: 'POST', // all queries and mutations will be sent to the tRPC Server as POST requests. }), ], });

Dig deeper

You can read more details by drilling into the TypeScript definitions in