Router
A router is a plain, nestable object made up of procedures. Routers can also modify those procedures, which makes it easy to organize and extend your API.
INFO
A standalone procedure is also a router, so you can use all router features on individual procedures too.
Overview
Define a router as a plain JavaScript object where each key maps to a procedure:
import { os } from '@orpc/server'
const ping = os.handler(async () => 'ping')
const pong = os.handler(async () => 'pong')
export const router = {
ping,
pong,
nested: { ping, pong }
}WARNING
For compatibility, do not use these router keys: then, bind, valueOf, toString, toJSON.
Extending Router
You can extend a router with shared behavior. For example, by applying authentication middleware or attaching metadata to every procedure:
const router = os.use(requiredAuth).meta(requireAuthMeta).router({
ping,
pong,
nested: {
ping,
pong,
}
})DANGER
If you apply middleware with .use at both the router and procedure levels, it may run more than once. That duplication can hurt performance. To avoid redundant middleware execution, see our best practices for middleware deduplication.
Lazy Router
Routers can also be lazy-loaded. This is useful for code splitting and can improve cold start performance by deferring route initialization until it is needed.
const router = {
ping,
pong,
planet: os.lazy(() => import('./planet'))
}const PlanetSchema = z.object({
id: z.number().int().min(1),
name: z.string(),
description: z.string().optional(),
})
export const listPlanet = os
.input(
z.object({
limit: z.number().int().min(1).max(100).optional(),
cursor: z.number().int().min(0).default(0),
}),
)
.handler(async ({ input }) => {
// your list code here
return [{ id: 1, name: 'name' }]
})
export default {
list: listPlanet,
// ...
}Utilities
INFO
A standalone procedure is also a router, so these utilities work with procedures too.
Infer Router Inputs
Infers the input type for each procedure in the router.
import type { InferRouterInputs } from '@orpc/server'
export type Inputs = InferRouterInputs<typeof router>
type FindPlanetInput = Inputs['planet']['find']Infer Router Outputs
Infers the output type for each procedure in the router.
import type { InferRouterOutputs } from '@orpc/server'
export type Outputs = InferRouterOutputs<typeof router>
type FindPlanetOutput = Outputs['planet']['find']Infer Router Initial Contexts
Infers the initial context for each procedure in the router.
import type { InferRouterInitialContexts } from '@orpc/server'
export type InitialContexts = InferRouterInitialContexts<typeof router>
type FindPlanetInitialContext = InitialContexts['planet']['find']Infer Router Final Contexts
Infers the final context for each procedure in the router by combining the initial and injected context. This is the closest match to the context the procedure's handler receives.
import type { InferRouterFinalContexts } from '@orpc/server'
export type FinalContexts = InferRouterFinalContexts<typeof router>
type FindPlanetFinalContext = FinalContexts['planet']['find']Infer Router Errors
Infers the throwable errors each procedure in a router can produce.
import type { InferRouterErrors } from '@orpc/server'
export type Errors = InferRouterErrors<typeof router>
type FindPlanetError = Errors['planet']['find']Infer Router Error
Infers all possible throwable errors the entire router can produce. This is useful when you want a single type for router-wide error handling.
import type { InferRouterError } from '@orpc/server'
export type RouterError = InferRouterError<typeof router>
