Skip to content

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:

ts
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:

ts
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.

ts
const router = {
  ping,
  pong,
  planet: os.lazy(() => import('./planet'))
}
ts
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.

ts
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.

ts
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.

ts
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.

ts
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.

ts
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.

ts
import type { 
InferRouterError
} from '@orpc/server'
export type
RouterError
=
InferRouterError
<typeof
router
>

Released under the MIT License.