Skip to content

tRPC v12 isn’t on npm yet. The @trpc12/* packages on this site can’t be installed until it’s released. Use v11 today

tRPC

splitLink

Send each call down one of two chains, picked from its path, type or input.

On this page

splitLink({ condition, true, false }) sends a call down the true chain when condition returns true for it, and down false otherwise. Each branch is a link or an array of links. On a client made with router:, condition sees typed paths:

import {
  function createTrpcClient<TSource, const TLinks extends ReadonlyArray<TrpcLink<any, RouterOf<TSource>>>>(opts: TypedClientOptions<TSource, TLinks> & DuplicateSwitchCheck<TLinks> & UnmetNeedCheck<TLinks>): TrpcClient<RouterOf<TSource>, LinksContext<TLinks>, undefined, LinksTypes<TLinks>>createTrpcClient,
  function httpLink<TOpts extends HttpLinkOptions>(opts: TOpts): TrpcLink<HttpLinkDecl<TOpts>>httpLink,
  function routerType<TRouter>(): RouterType<TRouter>routerType,
  
function splitLink<TRouter = any, TTrue extends Chain = Chain, TFalse extends Chain = Chain>(opts: SplitLinkOptions<TRouter, TTrue, TFalse>): TrpcLink<BranchesDecl<{
    true: TTrue;
    false: TFalse;
}>, TRouter>
splitLink
,
function wsLink<TOpts extends WebSocketLinkOptions>(opts: TOpts): SocketLink<{
    form: FormOfOptions<TOpts>;
}>
wsLink
,
} from '@trpc12/trpc/client'; const
const client: TrpcClient<{
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}, {}, undefined, LinksTypes<...>>
client
=
createTrpcClient<RouterType<{
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}>, readonly [...]>(opts: TypedClientOptions<...>): TrpcClient<...>
createTrpcClient
({
TypedClientOptions<RouterType<{ post: { byId: Procedure<{ type: "query"; ctx: Context; meta: {}; input: { id: string; }; output: Post; errors: TrpcError<"NOT_FOUND", { id: string; }> | SchemaValidationError<ZodObject<{ id: ZodString; }, $strip>>; services: never; }>; list: Procedure<...>; create: Procedure<...>; }; }>, readonly [...]>.router: RouterType<{
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}>
router
:
routerType<{
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}>(): RouterType<...>
routerType
<
type AppRouter = {
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}
AppRouter
>(),
TypedClientOptions<RouterType<{ post: { byId: Procedure<{ type: "query"; ctx: Context; meta: {}; input: { id: string; }; output: Post; errors: TrpcError<"NOT_FOUND", { id: string; }> | SchemaValidationError<ZodObject<{ id: ZodString; }, $strip>>; services: never; }>; list: Procedure<...>; create: Procedure<...>; }; }>, readonly [...]>.links: readonly [TrpcLink<BranchesDecl<{
    true: SocketLink<{
        form: JsonForm;
    }>;
    false: TrpcLink<HttpLinkDecl<{
        url: string;
        batch: true;
    }>, any>;
}>, {
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}>]
links
: [
splitLink<{
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}, SocketLink<...>, TrpcLink<...>>(opts: SplitLinkOptions<...>): TrpcLink<...>
splitLink
({
SplitLinkOptions<{ post: { byId: Procedure<{ type: "query"; ctx: Context; meta: {}; input: { id: string; }; output: Post; errors: TrpcError<"NOT_FOUND", { id: string; }> | SchemaValidationError<ZodObject<{ id: ZodString; }, $strip>>; services: never; }>; list: Procedure<...>; create: Procedure<...>; }; }, SocketLink<...>, TrpcLink<...>>.condition: (op: Operation<{}> & {
    readonly path: "post.byId" | "post.list" | "post.create";
}) => boolean
condition
: (
op: Operation<{}> & {
    readonly path: "post.byId" | "post.list" | "post.create";
}
op
) =>
op: Operation<{}> & {
    readonly path: "post.byId" | "post.list" | "post.create";
}
op
.Operation<{}>.type: ProcedureTypetype === 'subscription',
SplitLinkOptions<{ post: { byId: Procedure<{ type: "query"; ctx: Context; meta: {}; input: { id: string; }; output: Post; errors: TrpcError<"NOT_FOUND", { id: string; }> | SchemaValidationError<ZodObject<{ id: ZodString; }, $strip>>; services: never; }>; list: Procedure<...>; create: Procedure<...>; }; }, SocketLink<...>, TrpcLink<...>>.true: SocketLink<{
    form: JsonForm;
}>
true
:
wsLink<{
    url: string;
}>(opts: {
    url: string;
}): SocketLink<{
    form: JsonForm;
}>
wsLink
({ url: stringurl: 'ws://localhost:3000/trpc' }),
SplitLinkOptions<{ post: { byId: Procedure<{ type: "query"; ctx: Context; meta: {}; input: { id: string; }; output: Post; errors: TrpcError<"NOT_FOUND", { id: string; }> | SchemaValidationError<ZodObject<{ id: ZodString; }, $strip>>; services: never; }>; list: Procedure<...>; create: Procedure<...>; }; }, SocketLink<...>, TrpcLink<...>>.false: TrpcLink<HttpLinkDecl<{
    url: string;
    batch: true;
}>, any>
false
:
httpLink<{
    url: string;
    batch: true;
}>(opts: {
    url: string;
    batch: true;
}): TrpcLink<HttpLinkDecl<{
    url: string;
    batch: true;
}>, any>
httpLink
({ url: stringurl: 'http://localhost:3000/trpc', batch: truebatch: true }),
}), ], });

Calls get the call options and errors that the links of either branch declare. An operation type is missing only if every branch lacks it, and the link provides only what every branch provides (Custom links). For more than two branches, or to let a call pick its branch, use switchLink.

One client, several backends

A link can change the operation it passes on. That lets one client cover routers served by different backends, even ones with different contexts:

const const unprefix: (prefix: string) => TrpcLink<{}, any>unprefix = (prefix: stringprefix: string) =>
  link<{}>(fn: (opts: EffectLinkOpts<{}>) => OperationStream): TrpcLink<{}, any>link((opts: EffectLinkOpts<{}>opts) =>
    opts: EffectLinkOpts<{}>opts.EffectLinkOpts<{}>.next: (op: Operation) => OperationStreamnext({ ...opts: EffectLinkOpts<{}>opts.EffectLinkOpts<{}>.op: Operation<{}>op, Operation<{}>.path: stringpath: opts: EffectLinkOpts<{}>opts.EffectLinkOpts<{}>.op: Operation<{}>op.Operation<{}>.path: stringpath.String.slice(start?: number, end?: number): stringslice(prefix: stringprefix.String.length: numberlength + 1) }),
  );

createTrpcClient<RouterType<{
    blog: BlogRouter;
    shop: ShopRouter;
}>, readonly [TrpcLink<BranchesDecl<{
    true: (TrpcLink<{}, any> | TrpcLink<{
        form: JsonForm;
        provides: "response";
    }, any>)[];
    false: (TrpcLink<{}, any> | TrpcLink<{
        form: JsonForm;
        provides: "response";
    }, any>)[];
}>, {
    blog: BlogRouter;
    shop: ShopRouter;
}>]>(opts: TypedClientOptions<RouterType<{
    blog: BlogRouter;
    shop: ShopRouter;
}>, readonly [TrpcLink<BranchesDecl<{
    true: (TrpcLink<{}, any> | TrpcLink<{
        form: JsonForm;
        provides: "response";
    }, any>)[];
    false: (TrpcLink<{}, any> | TrpcLink<{
        form: JsonForm;
        provides: "response";
    }, any>)[];
}>, {
    blog: BlogRouter;
    shop: ShopRouter;
}>]>): TrpcClient<...>
createTrpcClient
({
TypedClientOptions<RouterType<{ blog: BlogRouter; shop: ShopRouter; }>, readonly [TrpcLink<BranchesDecl<{ true: (TrpcLink<{}, any> | TrpcLink<{ form: JsonForm; provides: "response"; }, any>)[]; false: (TrpcLink<...> | TrpcLink<...>)[]; }>, { blog: BlogRouter; shop: ShopRouter; }>]>.router: RouterType<{
    blog: BlogRouter;
    shop: ShopRouter;
}>
router
:
routerType<{
    blog: BlogRouter;
    shop: ShopRouter;
}>(): RouterType<{
    blog: BlogRouter;
    shop: ShopRouter;
}>
routerType
<{
blog: {
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}
blog
:
type BlogRouter = {
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}
BlogRouter
;
shop: {
    cart: Procedure<{
        type: "query";
        ctx: Context;
        meta: {};
        input: undefined;
        output: string[];
        errors: never;
        services: never;
    }>;
}
shop
:
type ShopRouter = {
    cart: Procedure<{
        type: "query";
        ctx: Context;
        meta: {};
        input: undefined;
        output: string[];
        errors: never;
        services: never;
    }>;
}
ShopRouter
}>(),
TypedClientOptions<RouterType<{ blog: BlogRouter; shop: ShopRouter; }>, readonly [TrpcLink<BranchesDecl<{ true: (TrpcLink<{}, any> | TrpcLink<{ form: JsonForm; provides: "response"; }, any>)[]; false: (TrpcLink<...> | TrpcLink<...>)[]; }>, { blog: BlogRouter; shop: ShopRouter; }>]>.links: readonly [TrpcLink<BranchesDecl<{
    true: (TrpcLink<{}, any> | TrpcLink<{
        form: JsonForm;
        provides: "response";
    }, any>)[];
    false: (TrpcLink<{}, any> | TrpcLink<{
        form: JsonForm;
        provides: "response";
    }, any>)[];
}>, {
    blog: BlogRouter;
    shop: ShopRouter;
}>]
links
: [
splitLink<{
    blog: BlogRouter;
    shop: ShopRouter;
}, (TrpcLink<{}, any> | TrpcLink<{
    form: JsonForm;
    provides: "response";
}, any>)[], (TrpcLink<{}, any> | TrpcLink<{
    form: JsonForm;
    provides: "response";
}, any>)[]>(opts: SplitLinkOptions<{
    blog: BlogRouter;
    shop: ShopRouter;
}, (TrpcLink<{}, any> | TrpcLink<{
    form: JsonForm;
    provides: "response";
}, any>)[], (TrpcLink<{}, any> | TrpcLink<{
    form: JsonForm;
    provides: "response";
}, any>)[]>): TrpcLink<...>
splitLink
({
SplitLinkOptions<{ blog: BlogRouter; shop: ShopRouter; }, (TrpcLink<{}, any> | TrpcLink<{ form: JsonForm; provides: "response"; }, any>)[], (TrpcLink<{}, any> | TrpcLink<...>)[]>.condition: (op: Operation<{}> & {
    readonly path: "shop.cart" | "blog.post.byId" | "blog.post.list" | "blog.post.create";
}) => boolean
condition
: (
op: Operation<{}> & {
    readonly path: "shop.cart" | "blog.post.byId" | "blog.post.list" | "blog.post.create";
}
op
) =>
op: Operation<{}> & {
    readonly path: "shop.cart" | "blog.post.byId" | "blog.post.list" | "blog.post.create";
}
op
.path: "shop.cart" | "blog.post.byId" | "blog.post.list" | "blog.post.create"path.String.startsWith(searchString: string, position?: number): booleanstartsWith('shop.'),
SplitLinkOptions<{ blog: BlogRouter; shop: ShopRouter; }, (TrpcLink<{}, any> | TrpcLink<{ form: JsonForm; provides: "response"; }, any>)[], (TrpcLink<{}, any> | TrpcLink<...>)[]>.true: (TrpcLink<{}, any> | TrpcLink<{
    form: JsonForm;
    provides: "response";
}, any>)[]
true
: [const unprefix: (prefix: string) => TrpcLink<{}, any>unprefix('shop'),
httpLink<{
    url: string;
}>(opts: {
    url: string;
}): TrpcLink<{
    form: JsonForm;
    provides: "response";
}, any>
httpLink
({ url: stringurl: const shopUrl: stringshopUrl })],
SplitLinkOptions<{ blog: BlogRouter; shop: ShopRouter; }, (TrpcLink<{}, any> | TrpcLink<{ form: JsonForm; provides: "response"; }, any>)[], (TrpcLink<{}, any> | TrpcLink<...>)[]>.false: (TrpcLink<{}, any> | TrpcLink<{
    form: JsonForm;
    provides: "response";
}, any>)[]
false
: [const unprefix: (prefix: string) => TrpcLink<{}, any>unprefix('blog'),
httpLink<{
    url: string;
}>(opts: {
    url: string;
}): TrpcLink<{
    form: JsonForm;
    provides: "response";
}, any>
httpLink
({ url: stringurl: const blogUrl: stringblogUrl })],
}), ], });