When your API grows large, importing every router module at startup can meaningfully increase cold start times — especially on serverless platforms like Cloudflare Workers, AWS Lambda, and Vercel Edge Functions where every millisecond of initialization counts. Lazy routers solve this by wrapping a sub-router in a dynamicDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/middleapi/orpc/llms.txt
Use this file to discover all available pages before exploring further.
import() that only runs the first time a request matches a procedure in that sub-router.
How it works
Thelazy() function from @orpc/server wraps a dynamic import into a Lazy<T> object. oRPC recognizes this wrapper and defers loading until the router is actually needed:
The dynamic import must return
{ default: router } — the same shape as an ES module default export. Use .then(m => ({ default: m.yourExport })) when your export is not the default.Lazy with os.lazy()
You can also apply middleware and other options to a lazy router using os.lazy():
Lazy type
TheLazy<T> interface wraps any router type:
Lazy<U> is accepted anywhere a Router is accepted (as Lazyable<Router>), your client types and OpenAPI spec remain identical whether or not a sub-router is lazy.
When to use lazy loading
Lazy routers are most beneficial when:- You are deploying to a serverless or edge environment where cold starts are measured and billed.
- Your router tree has large sub-routers that are infrequently called (e.g., admin APIs, reporting endpoints).
- You import heavy third-party libraries (database drivers, PDF generators, etc.) inside specific routers.
Example: splitting a large router
Before:router.ts
router.ts
