Skip to content
tRPC

Split Link

On this page

splitLink is a link that allows you to branch your link chain's execution depending on a given condition. Both the true and false branches are required. You can provide just one link, or multiple links per branch via an array.

It's important to note that when you provide links for splitLink to execute, splitLink will create an entirely new link chain based on the links you passed. Therefore, you need to use a terminating link if you only provide one link or add the terminating link at the end of the array if you provide multiple links to be executed on a branch. Here's a visual representation of how splitLink works:

Usage Example

Disable batching for certain requests

Let's say you're using httpBatchLink as the terminating link in your tRPC client config. This means request batching is enabled in every request. However, if you need to disable batching only for certain requests, you would need to change the terminating link in your tRPC client config dynamically between httpLink and httpBatchLink. This is a perfect opportunity for splitLink to be used:

1. Configure client / utils/trpc.ts

client/index.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,
  function httpLink<TRouter extends AnyRouter = AnyRouter>(opts: HTTPLinkOptions<TRouter["_def"]["_config"]["$types"]>): TRPCLink<TRouter>httpLink,
  
function splitLink<TRouter extends AnyRouter = AnyRouter>(opts: {
    condition: (op: Operation) => boolean;
    true: TRPCLink<TRouter> | TRPCLink<TRouter>[];
    false: TRPCLink<TRouter> | TRPCLink<TRouter>[];
}): TRPCLink<TRouter>
splitLink
,
} from '@trpc/client'; import type {
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{}>> & DecorateCreateRouterOptions<{}>
AppRouter
} from './server';
const const url: "http://localhost:3000"url = `http://localhost:3000`; 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
: [
splitLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{}>>>(opts: {
    condition: (op: Operation) => boolean;
    true: TRPCLink<BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{}>>> | TRPCLink<BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<...>>>[];
    false: TRPCLink<...> | TRPCLink<...>[];
}): TRPCLink<...>
splitLink
({
condition: (op: Operation) => booleancondition(op: Operationop) { // check for context property `skipBatch` return
var Boolean: BooleanConstructor
<unknown>(value?: unknown) => boolean
Boolean
(op: Operationop.context: OperationContextcontext.unknownskipBatch);
}, // when condition is true, use normal request
true: TRPCLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{}>>> | TRPCLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{}>>>[]
true
:
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, }), // when condition is false, use batching
false: TRPCLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{}>>> | TRPCLink<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{}>>>[]
false
:
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, }), }), ], });

2. Perform request without batching

client.ts
const const postResult: TRPCTaggedPromise<never[], DefaultErrorShape>postResult = 
const proxy: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    posts: QueryProcedure<{
        input: void;
        output: never[];
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>>
proxy
.
posts: {
    query: Resolver<{
        input: void;
        output: never[];
        errorShape: DefaultErrorShape;
        transformer: false;
    }>;
}
posts
.query: (input: void, opts?: TRPCProcedureOptions) => TRPCTaggedPromise<never[], DefaultErrorShape>query(var undefinedundefined, {
TRPCProcedureOptions.context?: ClientContext | undefinedcontext: { skipBatch: booleanskipBatch: true, }, });

or:

MyComponent.tsx
import { 
const trpc: CreateTRPCReactBase<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    posts: QueryProcedure<{
        input: void;
        output: {
            id: number;
            title: string;
        }[];
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, unknown> & DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    posts: QueryProcedure<{
        input: void;
        output: {
            id: number;
            title: string;
        }[];
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
} from './trpc';
export function function MyComponent(): React.JSX.ElementMyComponent() { const
const postsQuery: UseTRPCQueryResult<{
    id: number;
    title: string;
}[], TRPCClientErrorLike<{
    input: void;
    output: {
        id: number;
        title: string;
    }[];
    transformer: false;
    errorShape: DefaultErrorShape;
}>>
postsQuery
=
const trpc: CreateTRPCReactBase<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    posts: QueryProcedure<{
        input: void;
        output: {
            id: number;
            title: string;
        }[];
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>, unknown> & DecorateRouterRecord<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    posts: QueryProcedure<{
        input: void;
        output: {
            id: number;
            title: string;
        }[];
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>>
trpc
.
posts: DecoratedQuery<{
    input: void;
    output: {
        id: number;
        title: string;
    }[];
    transformer: false;
    errorShape: DefaultErrorShape;
}>
posts
.
useQuery: ProcedureUseQuery
<{
    id: number;
    title: string;
}[], {
    id: number;
    title: string;
}[]>(input: void | unique symbol, opts?: UseTRPCQueryOptions<{
    id: number;
    title: string;
}[], {
    id: number;
    title: string;
}[], TRPCClientErrorLike<{
    input: void;
    output: {
        id: number;
        title: string;
    }[];
    transformer: false;
    errorShape: DefaultErrorShape;
}>, {
    id: number;
    title: string;
}[]> | undefined) => UseTRPCQueryResult<{
    id: number;
    title: string;
}[], TRPCClientErrorLike<{
    input: void;
    output: {
        id: number;
        title: string;
    }[];
    transformer: false;
    errorShape: DefaultErrorShape;
}>> (+1 overload)
useQuery
(var undefinedundefined, {
TRPCUseQueryBaseOptions.trpc?: TRPCReactRequestOptions | undefinedtrpc: { context?: OperationContext | undefinedcontext: { skipBatch: booleanskipBatch: true, }, } }); 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(
const postsQuery: UseTRPCQueryResult<{
    id: number;
    title: string;
}[], TRPCClientErrorLike<{
    input: void;
    output: {
        id: number;
        title: string;
    }[];
    transformer: false;
    errorShape: DefaultErrorShape;
}>>
postsQuery
.
data: {
    id: number;
    title: string;
}[] | undefined
data
?? null, null, 4)}</React.JSX.IntrinsicElements.pre: React.DetailedHTMLProps<React.HTMLAttributes<HTMLPreElement>, HTMLPreElement>pre>
) }

The splitLink function takes an options object that has three fields: condition, true, and false.

declare function 
function splitLink<TRouter extends unknown = any>(opts: {
    condition: (op: Operation) => boolean;
    true: TRPCLink<TRouter> | TRPCLink<TRouter>[];
    false: TRPCLink<TRouter> | TRPCLink<TRouter>[];
}): TRPCLink<TRouter>
splitLink
<
function (type parameter) TRouter in splitLink<TRouter extends unknown = any>(opts: {
    condition: (op: Operation) => boolean;
    true: TRPCLink<TRouter> | TRPCLink<TRouter>[];
    false: TRPCLink<TRouter> | TRPCLink<TRouter>[];
}): TRPCLink<TRouter>
TRouter
extends type AnyRouter = anyAnyRouter = type AnyRouter = anyAnyRouter>(
opts: {
    condition: (op: Operation) => boolean;
    true: TRPCLink<TRouter> | TRPCLink<TRouter>[];
    false: TRPCLink<TRouter> | TRPCLink<TRouter>[];
}
opts
: {
condition: (op: Operation) => booleancondition: (op: anyop: type Operation = anyOperation) => boolean; /** * The link to execute next if the test function returns `true`. */ true: anytrue: type TRPCLink<T> = anyTRPCLink<
function (type parameter) TRouter in splitLink<TRouter extends unknown = any>(opts: {
    condition: (op: Operation) => boolean;
    true: TRPCLink<TRouter> | TRPCLink<TRouter>[];
    false: TRPCLink<TRouter> | TRPCLink<TRouter>[];
}): TRPCLink<TRouter>
TRouter
> | type TRPCLink<T> = anyTRPCLink<
function (type parameter) TRouter in splitLink<TRouter extends unknown = any>(opts: {
    condition: (op: Operation) => boolean;
    true: TRPCLink<TRouter> | TRPCLink<TRouter>[];
    false: TRPCLink<TRouter> | TRPCLink<TRouter>[];
}): TRPCLink<TRouter>
TRouter
>[];
/** * The link to execute next if the test function returns `false`. */ false: anyfalse: type TRPCLink<T> = anyTRPCLink<
function (type parameter) TRouter in splitLink<TRouter extends unknown = any>(opts: {
    condition: (op: Operation) => boolean;
    true: TRPCLink<TRouter> | TRPCLink<TRouter>[];
    false: TRPCLink<TRouter> | TRPCLink<TRouter>[];
}): TRPCLink<TRouter>
TRouter
> | type TRPCLink<T> = anyTRPCLink<
function (type parameter) TRouter in splitLink<TRouter extends unknown = any>(opts: {
    condition: (op: Operation) => boolean;
    true: TRPCLink<TRouter> | TRPCLink<TRouter>[];
    false: TRPCLink<TRouter> | TRPCLink<TRouter>[];
}): TRPCLink<TRouter>
TRouter
>[];
}): type TRPCLink<T> = anyTRPCLink<
function (type parameter) TRouter in splitLink<TRouter extends unknown = any>(opts: {
    condition: (op: Operation) => boolean;
    true: TRPCLink<TRouter> | TRPCLink<TRouter>[];
    false: TRPCLink<TRouter> | TRPCLink<TRouter>[];
}): TRPCLink<TRouter>
TRouter
>;

Reference

You can check out the source code for this link on GitHub.