Server-side SSE ping configuration
```ts
import { initTRPC } from '@trpc/server';
export const t = initTRPC.create({
sse: {
ping: {
enabled: true,
intervalMs: 2_000,
},
},
});
```
This example shows how to configure the server to send periodic ping messages to keep the connection alive.
httpSubscriptionLink React Native compatibility requires multiple polyfills
React Native does not natively support EventSource, Streams API, or AsyncIterators. All three must be ponyfilled for httpSubscriptionLink to work in React Native.
React Native EventSource polyfill must use networking library
For React Native, use a polyfill that utilizes React Native's networking library instead of XMLHttpRequest-based polyfills. XMLHttpRequest-based polyfills fail to reconnect after the app is backgrounded. The rn-eventsource-reborn package is recommended.
React Native httpSubscriptionLink polyfill setup
```ts
import '@azure/core-asynciterator-polyfill';
import { RNEventSource } from 'rn-eventsource-reborn';
import { ReadableStream, TransformStream } from 'web-streams-polyfill';
globalThis.ReadableStream = globalThis.ReadableStream || ReadableStream;
globalThis.TransformStream = globalThis.TransformStream || TransformStream;
```
This example shows how to set up the required polyfills for httpSubscriptionLink in React Native. Add this before the link is used, such as where you add your TRPCReact.Provider.
HTTPSubscriptionLinkOptions type definition
type HTTPSubscriptionLinkOptions<TRoot extends AnyClientTypes, TEventSource extends EventSourceLike.AnyConstructor = typeof EventSource> = {
url: string | (() => string | Promise<string>);
connectionParams?: Record<string, string> | null | (() => Record<string, string> | null | Promise<Record<string, string> | null>);
transformer?: DataTransformerOptions;
EventSource?: TEventSource;
eventSourceOptions?: EventSourceLike.InitDictOf<TEventSource> | ((opts: { op: Operation; }) => EventSourceLike.InitDictOf<TEventSource> | Promise<EventSourceLike.InitDictOf<TEventSource>>);
};
The url is required and can be a string or async function. connectionParams, transformer, EventSource, and eventSourceOptions are all optional.
SSEStreamProducerOptions server-side interface
export interface SSEStreamProducerOptions<TValue = unknown> {
ping?: { enabled: boolean; intervalMs?: number; };
maxDurationMs?: number;
emitAndEndImmediately?: boolean;
client?: { reconnectAfterInactivityMs?: number; };
}
ping.enabled defaults to false. ping.intervalMs defaults to 1000ms. maxDurationMs defaults to undefined. emitAndEndImmediately defaults to false and is only useful for serverless runtimes. client options are sent to the client as part of the first message.
Links execute in order on request and reverse on response
Links are composed together into an array provided to the tRPC client configuration via the links property, forming a link chain. The tRPC client executes the links in the order they are added to the links array when doing a request and executes them in reverse order when handling a response.
Links maintain and can modify operation context
As an operation moves along your link chain, it maintains a context that each link can read and modify. This allows links to pass metadata along the chain that other links use in their execution logic. Obtain the current context object and modify it by accessing op.context. You can set the context object's initial value for a particular operation by providing the context parameter to the query or useQuery hook, mutation, subscription, and similar methods.
httpBatchLink is the recommended terminating link
httpBatchLink is the recommended terminating link by tRPC. Other terminating link examples include httpLink, httpBatchStreamLink, httpSubscriptionLink, wsLink, and localLink depending on your needs.
Terminating link is the last link in the chain
The terminating link is the last link in a link chain. Instead of calling the next function, the terminating link is responsible for sending the composed tRPC operation to the tRPC server and returning an OperationResultEnvelope. The links array must have at least one link and that link should be a terminating link. If links do not have a terminating link at the end, the tRPC operation will not be sent to the server.
Custom link implementation example
import { TRPCLink } from '@trpc/client';
import { observable } from '@trpc/server/observable';
import type { AppRouter } from './server';
export const customLink: TRPCLink<AppRouter> = () => {
return ({ next, op }) => {
return observable((observer) => {
console.log('performing operation:', op);
const unsubscribe = next(op).subscribe({
next(value) {
console.log('we received value', value);
observer.next(value);
},
error(err) {
console.log('we received error', err);
observer.error(err);
},
complete() {
observer.complete();
},
});
return unsubscribe;
});
};
};
TRPCLink type structure with three function layers
A link follows the TRPCLink type and is composed of three nested functions. The first function is the setup phase that happens once per app and is useful for storing caches or state. The second function receives an object with op (the Operation being executed) and next (function to call the next link). The third function returns an observable from @trpc/server that accepts an observer to notify the next link up the chain how to handle the operation result.
Links enable customization of data flow between client and server
Links enable you to customize the flow of data between the tRPC Client and Server. A link should do only one thing, which can be either a self-contained modification to a tRPC operation (query, mutation, or subscription) or a side-effect based on the operation such as logging.
splitLink with React Query context
When using tRPC with React Query, you can pass context through the trpc options in useQuery:
```tsx
const postsQuery = trpc.posts.useQuery(undefined, {
trpc: {
context: {
skipBatch: true,
},
}
});
```
splitLink overview and purpose
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.
splitLink requires terminating link in each branch
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.
splitLink API signature
The splitLink function takes an options object with three required fields: condition, true, and false. The condition field is a function that takes an Operation and returns a boolean. The true field is either a single TRPCLink or an array of TRPCLink objects to execute when condition returns true. The false field is either a single TRPCLink or an array of TRPCLink objects to execute when condition returns false.
splitLink example: disable batching for certain requests
This example shows how to use splitLink to conditionally route requests between httpLink (no batching) and httpBatchLink (with batching) based on a context property. The condition checks for op.context.skipBatch and routes to httpLink when true, and httpBatchLink when false:
```ts
const client = createTRPCClient<AppRouter>({
links: [
splitLink({
condition(op) {
return Boolean(op.context.skipBatch);
},
true: httpLink({
url: 'http://localhost:3000',
}),
false: httpBatchLink({
url: 'http://localhost:3000',
}),
}),
],
});
```
splitLink with context in client.query
When using splitLink, you can pass context at query time to influence the condition. For example, to skip batching for a specific query:
```ts
const postResult = proxy.posts.query(undefined, {
context: {
skipBatch: true,
},
});
```
retryLink retry function parameters
The retry function receives RetryFnOptions with three properties: op (the operation that failed, containing id, type, input, and path), error (the TRPCClientError that occurred), and attempts (the number of attempts that have been made, including the first call).
retryLink configuration options
RetryLinkOptions interface has two properties: retry (required) which is a function that takes RetryFnOptions and returns boolean to determine when to retry, and retryDelayMs (optional) which is a function that takes the attempt number and returns the delay in milliseconds between retries (defaults to 0).
retryLink usage example with httpBatchLink
Complete example: import { createTRPCClient, httpBatchLink, retryLink } from '@trpc/client'; const client = createTRPCClient<AppRouter>({ links: [ retryLink({ retry(opts) { if (opts.error.data && opts.error.data.code !== 'INTERNAL_SERVER_ERROR') { return false; } if (opts.op.type !== 'query') { return false; } return opts.attempts <= 3; }, retryDelayMs: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000), }), httpBatchLink({ url: 'http://localhost:3000', }), ], });
retryLink with subscriptions and tracked events
When using retryLink with subscriptions that use tracked(), the link automatically includes the last known event ID when retrying. This ensures that when a subscription reconnects, it can resume from where it left off without missing any events. For example, with Server-sent Events (SSE) and httpSubscriptionLink, retryLink automatically handles reconnecting with the last event ID when errors like 401 Unauthorized occur.
retryLink placement in links array
The retryLink can be placed before or after other links in the links array when creating your tRPC client, depending on your requirements.
retryLink purpose and when to use
The retryLink is a tRPC client link that allows you to retry failed operations by automatically retrying requests based on specified conditions. It handles transient errors such as network failures or server errors. If you use @trpc/react-query, you generally will not need this link as retry functionality is built into the useQuery() and useMutation() hooks from @tanstack/react-query.
retryLink with exponential backoff example
Example showing retryLink that retries only 500 errors on query operations up to 3 times with exponential backoff: retryDelayMs: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000) doubles the delay with each attempt starting at 1 second and capping at 30 seconds.
WebSocketClientOptions.experimental_encoder
experimental_encoder field in WebSocketClientOptions is optional. It specifies a custom encoder for wire encoding (e.g. custom binary formats). It defaults to jsonEncoder.
wsLink basic usage example
import { createTRPCClient, createWSClient, wsLink } from '@trpc/client';
import type { AppRouter } from './server';
const wsClient = createWSClient({
url: 'ws://localhost:3000',
});
const trpcClient = createTRPCClient<AppRouter>({
links: [wsLink<AppRouter>({ client: wsClient })],
});
WebSocketLinkOptions interface
WebSocketLinkOptions interface has the following fields: client (TRPCWebSocketClient, required) - the WebSocket client to use; transformer (DataTransformerOptions, optional) - data transformer for message serialization.
WebSocketClientOptions.url
url field in WebSocketClientOptions is required. It can be a string or a function that returns a string or Promise<string>, specifying the WebSocket URL to connect to.
WebSocketClientOptions.connectionParams
connectionParams field in WebSocketClientOptions is optional. It can be a Record<string, string>, null, or a function that returns Record<string, string> | null. These connection params are available in createContext() and are sent as the first message.
WebSocketClientOptions.WebSocket
WebSocket field in WebSocketClientOptions is optional. It is a ponyfill to specify which WebSocket implementation to use.
WebSocketClientOptions.retryDelayMs
retryDelayMs field in WebSocketClientOptions is optional. It specifies the number of milliseconds before a reconnect is attempted. It defaults to exponentialBackoff function.
WebSocketClientOptions.onOpen
onOpen field in WebSocketClientOptions is an optional callback function triggered when a WebSocket connection is established.
WebSocketClientOptions.onError
onError field in WebSocketClientOptions is an optional callback function triggered when a WebSocket connection encounters an error. It receives an optional Event parameter.
WebSocketClientOptions.onClose
onClose field in WebSocketClientOptions is an optional callback function triggered when a WebSocket connection is closed. It receives an optional object with a code field.
WebSocketClientOptions.lazy mode configuration
lazy field in WebSocketClientOptions is optional and controls lazy mode behavior. It has two sub-fields: enabled (boolean, default false) - enables lazy mode which closes WebSocket automatically after inactivity; closeMs (number, default 0) - milliseconds after which to close WebSocket when no messages or pending requests exist.
WebSocketClientOptions.keepAlive configuration
keepAlive field in WebSocketClientOptions is optional and configures ping/pong keep-alive messages. It has three sub-fields: enabled (boolean, default false) - enables keep-alive pings; intervalMs (number, default 5000) - milliseconds between ping messages; pongTimeoutMs (number, default 1000) - milliseconds to wait for pong before closing connection.
tRPC client setup example with httpBatchLink
const [trpcClient] = useState(() =>
trpc.createClient({
links: [
httpBatchLink({
url: 'http://localhost:3000/trpc',
async headers() {
return {
authorization: getAuthCookie(),
};
},
}),
],
}),
);
httpBatchLink configuration
The httpBatchLink link accepts a url property specifying the API endpoint (e.g., 'http://localhost:3000/trpc'), and an optional async headers function that returns an object of HTTP headers to send with requests.
Pass HTTP headers in httpBatchLink
The httpBatchLink accepts an async headers function that can dynamically return HTTP headers for each request. This is useful for adding authentication tokens or other request-specific headers.
tRPC token refresh link
trpc-token-refresh-link is a tRPC link for refreshing access tokens and refresh tokens.
httpBatchLink configuration
httpBatchLink is a client link that batches multiple requests together. It requires a url parameter specifying the server endpoint where requests will be sent.
HTTP batch link for client configuration
Use httpBatchLink in the client links array to automatically batch multiple procedure calls into a single HTTP request. Configure it with the server URL.
Transformers moved to links
In tRPC v11, data transformers are no longer configured when initializing the tRPC client. Instead, they must be added to the links array. For HTTP links, add the transformer option directly: httpBatchLink({ url: '/api/trpc', transformer: superjson }). For Next.js, add transformer to createTRPCNext: createTRPCNext<AppRouter>({ transformer: superjson }).
Streaming responses over HTTP
tRPC v11 supports streaming mutations and queries using httpBatchStreamLink. Query and mutation resolvers can be AsyncGenerators that yield data, allowing streaming responses over HTTP without WebSockets.
Promises embedded in nested data
The httpBatchStreamLink now allows promises to be embedded in nested data returned from query/mutation resolvers. A resolver can return an object with both instant values and promises that resolve later.
retryLink introduced
tRPC v11 introduces retryLink, a client link that allows retrying failed operations.
wsLink improvements
wsLink now supports passing a Promise in the url callback for servers that switch location during deploys, and includes a new lazy option that automatically disconnects the websocket when there are no pending requests.
Experimental form-data support replaced
All experimental form-data features have been replaced: experimental_formDataLink (use httpLink instead), experimental_parseMultipartFormData, experimental_isMultipartFormDataRequest, experimental_composeUploadHandlers, experimental_createMemoryUploadHandler, experimental_NodeOnDiskFile, experimental_createFileUploadHandler, and experimental_contentTypeHandlers are no longer available. See examples/next-formdata for the new approach.
Use splitLink to separate public and private requests for caching
You can use a splitLink to split public requests from those that should be private and uncached, allowing different cache strategies for different types of requests.
httpLink supports non-JSON content types out of the box
httpLink supports non-JSON content types out of the box. If you are only using httpLink, your existing setup should work immediately without additional configuration.
httpBatchLink and httpBatchStreamLink require splitLink for non-JSON content
If you are using httpBatchLink or httpBatchStreamLink, you will need to include a splitLink and route requests based on the content type. Use the isNonJsonSerializable helper to determine if input is non-JSON.
Client transformer must match server transformer for non-JSON content
If you are using a transformer in your tRPC server, TypeScript requires that your tRPC client link defines the transformer as well. When using splitLink with non-JSON content, the httpLink's transformer object must have serialize and deserialize methods, while the httpBatchLink's transformer can be used directly.
splitLink with transformer for non-JSON content
Example of splitLink configuration with superjson transformer for both non-JSON and JSON requests:
```ts
import {
createTRPCClient,
httpBatchLink,
httpLink,
isNonJsonSerializable,
splitLink,
} from '@trpc/client';
import superjson from 'superjson';
import type { AppRouter } from './server';
const url = 'http://localhost:2022';
createTRPCClient<AppRouter>({
links: [
splitLink({
condition: (op) => isNonJsonSerializable(op.input),
true: httpLink({
url,
transformer: {
serialize: (data) => data,
deserialize: (data) => superjson.deserialize(data),
},
}),
false: httpBatchLink({
url,
transformer: superjson,
}),
}),
],
});
```
httpBatchLink URL configuration for tRPC endpoint
Configure httpBatchLink with a url property pointing to the tRPC HTTP endpoint. Example: httpBatchLink({ url: 'http://localhost:3000/api/trpc' }). This URL should match the server-side route where tRPC requests are handled.