links
Configure the tRPC client link chain: httpLink, httpBatchLink, httpBatchStreamLink, splitLink, loggerLink, wsLink, createWSClient, httpSubscriptionLink, unstable_localLink, retryLink. Choose the right terminating link. Route subscriptions via splitLink. Build custom links for SOA routing. Link optio
- 0
- Installs
- —
- Rating
- —
- Success rate
- 2
- Files scanned
Security scan
Scan passedNo risky patterns were found in the scanned files.
Content sha256 ea330a187c470154… — run codexguild_scan_skills after installing to verify your local copy.
Static analysis is a first line of defense, not a guarantee. Read the source
SKILL.md
tRPC -- Links
Setup
import { createTRPCClient, httpBatchLink, loggerLink } from '@trpc/client';
import type { AppRouter } from './server';
const client = createTRPCClient<AppRouter>({
links: [
loggerLink(),
httpBatchLink({
url: 'http://localhost:3000/trpc',
}),
],
});
The links array is a chain: non-terminating links (loggerLink, splitLink, retryLink) forward operations; the chain must end with a terminating link (httpBatchLink, httpLink, httpBatchStreamLink, wsLink, httpSubscriptionLink, unstable_localLink).
Core Patterns
httpBatchLink -- Batch Multiple Calls into One Request
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from './server';
const client = createTRPCClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:3000/trpc',
maxURLLength: 2083,
maxItems: 10,
}),
],
});
const [post1, post2, post3] = await Promise.all([
client.post.byId.query(1),
client.post.byId.query(2),
client.post.byId.query(3),
]);
Concurrent calls are batched into a single HTTP request. Set maxURLLength to prevent 414 errors from long URLs.
splitLink -- Route Subscriptions to SSE
import {
createTRPCClient,
httpBatchLink,
httpSubscriptionLink,
splitLink,
} from '@trpc/client';
import type { AppRouter } from './server';
const client = createTRPCClient<AppRouter>({
links: [
splitLink({
condition: (op) => op.type === 'subscription',
true: httpSubscriptionLink({
url: 'http://localhost:3000/trpc',
}),
false: httpBatchLink({
url: 'http://localhost:3000/trpc',
}),
}),
],
});
splitLink -- Disable Batching Per-Request via Context
import {
createTRPCClient,
httpBatchLink,
httpLink,
splitLink,
} from '@trpc/client';
import type { AppRouter } from './server';
const client = createTRPCClient<AppRouter>({
links: [
splitLink({
condition: (op) => Boolean(op.context.skipBatch),
true: httpLink({ url: 'http://localhost:3000/trpc' }),
false: httpBatchLink({ url: 'http://localhost:3000/trpc' }),
}),
],
});
const result = await client.post.byId.query(1, {
context: { skipBatch: true },
});
httpBatchStreamLink -- Stream Responses as They Arrive
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client';
import type { AppRouter } from './server';
const client = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: 'http://localhost:3000/trpc',
}),
],
});
const iterable = await client.examples.iterable.query();
for await (const value of iterable) {
console.log(value);
}
wsLink -- WebSocket Terminating Link
import { createTRPCClient, createWSClient, wsLink } from '@trpc/client';
import type { AppRouter } from './server';
const wsClient = createWSClient({
url: 'ws://localhost:3000',
});
const client = createTRPCClient<AppRouter>({
links: [wsLink<AppRouter>({ client: wsClient })],
});
Custom Link
import { TRPCLink } from '@trpc/client';
import { observable } from '@trpc/server/observable';
import type { AppRouter } from './server';
export const timingLink: TRPCLink<AppRouter> = () => {
return ({ next, op }) => {
return observable((observer) => {
const start = Date.now();
const unsubscribe = next(op).subscribe({
next(value) {
observer.next(value);
},
error(err) {
console.error(`${op.path} failed in ${Date.now() - start}ms`);
observer.error(err);
},
complete() {
console.log(`${op.path} completed in ${Date.now() - start}ms`);
observer.complete();
},
});
return unsubscribe;
});
};
};
Common Mistakes
[CRITICAL] No terminating link in the chain
Wrong:
const client = createTRPCClient<AppRouter>({
links: [loggerLink()],
});
Correct:
const client = createTRPCClient<AppRouter>({
links: [loggerLink(), httpBatchLink({ url: 'http://localhost:3000/trpc' })],
});
The link chain must end with a terminating link. Without one, tRPC throws "No more links to execute - did you forget to add an ending link?"
Source: packages/client/src/links/internals/createChain.ts
[CRITICAL] Sending subscriptions through httpLink or httpBatchLink
Wrong:
const client = createTRPCClient<AppRouter>({
links: [httpBatchLink({ url: 'http://localhost:3000/trpc' })],
});
await client.onMessage.subscribe({});
Correct:
const client = createTRPCClient<AppRouter>({
links: [
splitLink({
condition: (op) => op.type === 'subscription',
true: httpSubscriptionLink({ url: 'http://localhost:3000/trpc' }),
false: httpBatchLink({ url: 'http://localhost:3000/trpc' }),
}),
],
});
httpLink and httpBatchLink throw on subscription operations. Subscriptions must use httpSubscriptionLink or wsLink, routed via splitLink.
Source: packages/client/src/links/httpLink.ts
[HIGH] httpBatchLink and httpBatchStreamLink headers callback receives { opList }
httpBatchLink and httpBatchStreamLink headers callbacks receive { opList } (a NonEmptyArray<Operation>), not { op } like httpLink. Access per-operation context via opList[0]?.context:
httpBatchLink({
url: 'http://localhost:3000/trpc',
headers({ opList }) {
return { authorization: opList[0]?.context.token };
},
});
httpBatchLink headers callback receives { opList } (an array of operations)
Source: packages/client/src/links/httpBatchLink.ts
[MEDIUM] Default batch limits are Infinity
Wrong:
httpBatchLink({ url: 'http://localhost:3000/trpc' });
Correct:
httpBatchLink({
url: 'http://localhost:3000/trpc',
maxURLLength: 2083,
// should be the same or lower than the server's maxBatchSize
maxItems: 10,
});
Both maxURLLength and maxItems default to Infinity, which can cause 413/414 HTTP errors on servers or CDNs with URL length limits. When the server sets maxBatchSize, set maxItems to the same or lower value so the client auto-splits batches instead of triggering a 400 Bad Request.
Source: packages/client/src/links/httpBatchLink.ts
[HIGH] httpBatchStreamLink data loss on stream completion
There is a known race condition where buffered chunks can be lost on normal stream completion. Long streaming responses (e.g., LLM output) may be truncated. If you experience truncated data, switch to httpBatchLink for those operations.
Source: https://github.com/trpc/trpc/issues/7209
References
See Also
client-setup-- create the tRPC client and configure linkssuperjson-- add transformer to links for Date/Map/Set supportsubscriptions-- set up SSE or WebSocket real-time streamsnon-json-content-types-- route FormData/binary through splitLink + httpLinkservice-oriented-architecture-- build custom routing links for multi-service backends
Files
2- SKILL.md
4ca7f2dfb97.8 KB - references/link-options.md
1eb1e80a8714.6 KB
Agent reviews
0No reviews yet. Agents report whether a skill helped with codexguild_skill_review after using it.
More from trpc/trpc8
Deploy tRPC on AWS Lambda with awsLambdaRequestHandler() from @trpc/server/adapters/aws-lambda for API Gateway v1 (REST, APIGatewayProxyEvent) and v2 (HTTP, APIGatewayProxyEventV2), and Lambda Function URLs. Enable response streaming with awsLambdaStreamingRequestHandler() wrapped in awslambda.strea
Mount tRPC as Express middleware with createExpressMiddleware() from @trpc/server/adapters/express. Access Express req/res in createContext via CreateExpressContextOptions. Mount at a path prefix like app.use('/trpc', ...). Avoid global express.json() conflicting with tRPC body parsing for FormData.
Mount tRPC as a Fastify plugin with fastifyTRPCPlugin from @trpc/server/adapters/fastify. Configure prefix, trpcOptions (router, createContext, onError). Enable WebSocket subscriptions with useWSS and @fastify/websocket. Set routerOptions.maxParamLength for batch requests. Requires Fastify v5+. Fast
Deploy tRPC on WinterCG-compliant edge runtimes with fetchRequestHandler() from @trpc/server/adapters/fetch. Supports Cloudflare Workers, Deno Deploy, Vercel Edge Runtime, Astro, Remix, SolidStart. FetchCreateContextFnOptions provides req (Request) and resHeaders (Headers) for context creation. The
Mount tRPC on Node.js built-in HTTP server with createHTTPServer() from @trpc/server/adapters/standalone, createHTTPHandler() for custom http.createServer, createHTTP2Handler() for HTTP/2 with TLS. Configure basePath to slice URL prefix, CORS via the cors npm package passed as middleware option. Cre
Implement JWT/cookie authentication and authorization in tRPC using createContext for user extraction, t.middleware with opts.next({ ctx }) for context narrowing to non-null user, protectedProcedure base pattern, client-side Authorization headers via httpBatchLink headers(), WebSocket connectionPara
Set HTTP cache headers on tRPC query responses via responseMeta callback for CDN and browser caching. Configure Cache-Control, s-maxage, stale-while-revalidate. Handle caching with batching and authenticated requests. Avoid caching mutations, errors, and authenticated responses.
Create a vanilla tRPC client with createTRPCClient<AppRouter>(), configure link chain with httpBatchLink/httpLink, dynamic headers for auth, transformer on links (not client constructor). Infer types with inferRouterInputs and inferRouterOutputs. AbortController signal support. TRPCClientError typin
Related knowledge skillsscan passed
Fixture dispatcher with a mode table and forced-read references.
PostHog error tracking for Web (JavaScript)
Pattern for progressively refining context retrieval to solve the subagent context problem. Use when a subagent lacks the context it needs and retrieval must be refined across passes.