server-setup
Initialize tRPC with initTRPC.create(), define routers with t.router(), create procedures with .query()/.mutation()/.subscription(), configure context with createContext(), export AppRouter type, merge routers with t.mergeRouters(), lazy-load routers with lazy().
- 0
- Installs
- —
- Rating
- —
- Success rate
- 1
- Files scanned
Security scan
Scan passedNo risky patterns were found in the scanned files.
Content sha256 73df7ac1d8b892d4… — 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 -- Server Setup
Setup
// server/trpc.ts
import { initTRPC } from '@trpc/server';
const t = initTRPC.create();
export const router = t.router;
export const publicProcedure = t.procedure;
// server/appRouter.ts
import { z } from 'zod';
import { publicProcedure, router } from './trpc';
type User = { id: string; name: string };
export const appRouter = router({
userList: publicProcedure.query(async (): Promise<User[]> => {
return [{ id: '1', name: 'Katt' }];
}),
userById: publicProcedure
.input(z.string())
.query(async ({ input }): Promise<User> => {
return { id: input, name: 'Katt' };
}),
userCreate: publicProcedure
.input(z.object({ name: z.string() }))
.mutation(async ({ input }): Promise<User> => {
return { id: '1', ...input };
}),
});
export type AppRouter = typeof appRouter;
// server/index.ts
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { appRouter } from './appRouter';
const server = createHTTPServer({ router: appRouter });
server.listen(3000);
Core Patterns
Context with typed session
// server/context.ts
import type { CreateHTTPContextOptions } from '@trpc/server/adapters/standalone';
export async function createContext(opts: CreateHTTPContextOptions) {
const token = opts.req.headers['authorization'];
return { token };
}
export type Context = Awaited<ReturnType<typeof createContext>>;
// server/trpc.ts
import { initTRPC } from '@trpc/server';
import type { Context } from './context';
const t = initTRPC.context<Context>().create();
export const router = t.router;
export const publicProcedure = t.procedure;
// server/index.ts
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { appRouter } from './appRouter';
import { createContext } from './context';
const server = createHTTPServer({
router: appRouter,
createContext,
});
server.listen(3000);
Inner/outer context split for testability
// server/context.ts
import type { CreateHTTPContextOptions } from '@trpc/server/adapters/standalone';
import { db } from './db';
interface CreateInnerContextOptions {
session: { user: { email: string } } | null;
}
export async function createContextInner(opts?: CreateInnerContextOptions) {
return {
db,
session: opts?.session ?? null,
};
}
export async function createContext(opts: CreateHTTPContextOptions) {
const session = getSessionFromCookie(opts.req);
const contextInner = await createContextInner({ session });
return {
...contextInner,
req: opts.req,
res: opts.res,
};
}
export type Context = Awaited<ReturnType<typeof createContextInner>>;
Infer Context from createContextInner so server-side callers and tests never need HTTP request objects.
Merging child routers
// server/routers/user.ts
import { publicProcedure, router } from '../trpc';
export const userRouter = router({
list: publicProcedure.query(() => []),
});
// server/routers/post.ts
import { z } from 'zod';
import { publicProcedure, router } from '../trpc';
export const postRouter = router({
create: publicProcedure
.input(z.object({ title: z.string() }))
.mutation(({ input }) => ({ id: '1', ...input })),
list: publicProcedure.query(() => []),
});
// server/routers/_app.ts
import { router } from '../trpc';
import { postRouter } from './post';
import { userRouter } from './user';
export const appRouter = router({
user: userRouter,
post: postRouter,
});
export type AppRouter = typeof appRouter;
Lazy-loaded routers for serverless cold starts
// server/routers/_app.ts
import { lazy } from '@trpc/server';
import { router } from '../trpc';
export const appRouter = router({
// Short-hand when the module has exactly one router exported
greeting: lazy(() => import('./greeting.js')),
// Use .then() to pick a named export when the module exports multiple routers
user: lazy(() => import('./user.js').then((m) => m.userRouter)),
});
export type AppRouter = typeof appRouter;
Common Mistakes
[CRITICAL] Calling initTRPC.create() more than once
Wrong:
// file: userRouter.ts
import { initTRPC } from '@trpc/server';
const t = initTRPC.create();
export const userRouter = t.router({});
// file: postRouter.ts
import { initTRPC } from '@trpc/server';
const t2 = initTRPC.create();
export const postRouter = t2.router({});
Correct:
// file: trpc.ts (single file, created once)
import { initTRPC } from '@trpc/server';
import type { Context } from './context';
const t = initTRPC.context<Context>().create();
export const router = t.router;
export const publicProcedure = t.procedure;
Multiple tRPC instances cause type mismatches and runtime errors when routers from different instances are merged.
Source: www/docs/server/routers.md
[HIGH] Using reserved words as procedure names
Wrong:
import { publicProcedure, router } from './trpc';
const appRouter = router({
then: publicProcedure.query(() => 'hello'),
});
Correct:
import { publicProcedure, router } from './trpc';
const appRouter = router({
next: publicProcedure.query(() => 'hello'),
});
Router creation throws if procedure names are "then", "call", or "apply" because these conflict with JavaScript Proxy internals.
Source: packages/server/src/unstable-core-do-not-import/router.ts
[CRITICAL] Importing AppRouter as a value import
Wrong:
// client.ts
import { AppRouter } from '../server/router';
Correct:
// client.ts
import type { AppRouter } from '../server/router';
A non-type import pulls the entire server bundle into the client; use import type so it is stripped at build time.
Source: www/docs/server/routers.md
[MEDIUM] Creating context without inner/outer split
Wrong:
import type { CreateExpressContextOptions } from '@trpc/server/adapters/express';
export function createContext({ req }: CreateExpressContextOptions) {
return { db: prisma, user: getUserFromReq(req) };
}
Correct:
import type { CreateExpressContextOptions } from '@trpc/server/adapters/express';
export function createContextInner(opts: { user?: User }) {
return { db: prisma, user: opts.user ?? null };
}
export function createContext({ req }: CreateExpressContextOptions) {
return createContextInner({ user: getUserFromReq(req) });
}
Without an inner context factory, server-side callers and tests must construct HTTP request objects to get context.
Source: www/docs/server/context.md
[HIGH] Merging routers with different transformers
Wrong:
import { initTRPC } from '@trpc/server';
import superjson from 'superjson';
const t1 = initTRPC.create({ transformer: superjson });
const t2 = initTRPC.create();
const router1 = t1.router({ a: t1.procedure.query(() => 'a') });
const router2 = t2.router({ b: t2.procedure.query(() => 'b') });
t1.mergeRouters(router1, router2);
Correct:
import { initTRPC } from '@trpc/server';
import superjson from 'superjson';
const t = initTRPC.create({ transformer: superjson });
const router1 = t.router({ a: t.procedure.query(() => 'a') });
const router2 = t.router({ b: t.procedure.query(() => 'b') });
t.mergeRouters(router1, router2);
t.mergeRouters() throws at runtime if the routers were created with different transformer or errorFormatter configurations.
Source: packages/server/src/unstable-core-do-not-import/router.ts
[CRITICAL] Importing appRouter value into client code
Wrong:
// client.ts
import { appRouter } from '../server/router';
type AppRouter = typeof appRouter;
Correct:
// client.ts
import type { AppRouter } from '../server/router';
// server/router.ts
export type AppRouter = typeof appRouter;
Importing the appRouter value bundles the entire server into the client, even if you only use typeof.
Source: www/docs/server/routers.md
See Also
middlewares-- add auth, logging, context extension to proceduresvalidators-- add input/output validation with Zoderror-handling-- throw and format typed errorsserver-side-calls-- call procedures from server codeadapter-standalone-- mount on Node.js HTTP serveradapter-fetch-- mount on edge runtimes
Files
1- SKILL.md
eb62121f278.9 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 backend skillsscan passed
PostHog logs for Node.js
REST API design patterns including resource naming, status codes, pagination, filtering, error responses, versioning, and rate limiting for production APIs. Use when designing or reviewing REST endpoints, resource names, status codes, pagination, or versioning.
Report browser/API/CLI/job/worker/webhook bugs. (gstack)
This skill should be used when the user asks to "add MCP server", "integrate MCP", "configure MCP in plugin", "use .mcp.json", "set up Model Context Protocol", "connect external service", mentions "${CLAUDE_PLUGIN_ROOT} with MCP", or discusses MCP server types (SSE, stdio, HTTP, WebSocket). Provides
Identifies external providers, merchants, nonprofits, platforms, APIs, and software services, and resolves the documented way to engage them — to pay, donate, subscribe, book, provision, or integrate with them. MUST be used BEFORE web search, model memory, or any other directory/vendor-lookup skill
Guides stable API and interface design. Use when designing APIs, module boundaries, or any public interface. Use when creating REST or GraphQL endpoints, defining type contracts between modules, or establishing boundaries between frontend and backend.