Routers
Organizing oRPC routers
Router Structure
Routers live in src/rpc/procedures/routers/ and are grouped by feature.
src/rpc/procedures/routers/
├── auth.ts
├── organizations.ts
├── members.ts
├── api-keys.ts
└── ...Create a Router
// src/rpc/procedures/routers/my-feature.ts
import { authProcedure, createRPCRouter } from "@/rpc/procedures/rpc";
import { z } from "zod";
export const myFeatureRouter = createRPCRouter({
list: authProcedure
.meta({ rateLimit: "QUERY" })
.query(async ({ ctx }) => {
return { success: true, payload: await ctx.db.myFeature.list() };
}),
upsert: authProcedure
.meta({ rateLimit: "MUTATION" })
.input(z.object({ id: z.string().optional(), name: z.string() }))
.mutation(async ({ ctx, input }) => {
return { success: true, payload: await ctx.db.myFeature.upsert(input) };
}),
});Register in Root Router
// src/rpc/procedures/root.ts
import { createRPCRouter } from "@/rpc/procedures/rpc";
import { myFeatureRouter } from "@/rpc/procedures/routers/my-feature";
export const appRouter = createRPCRouter({
myFeature: myFeatureRouter,
});Best Practices
- Keep routers feature-scoped.
- Use shared schemas from
src/features/<feature>/schema.ts. - Set
rateLimitmetadata explicitly. - Return
ActionResponsefor predictable client behavior. - Add
.route(...)only for procedures you want exposed via REST/OpenAPI.