feat: Lazy load routers
Problem
Describe the feature you'd like to request Basically `next/dynamic` but for the backend. Recently our tRPC router has been growing significantly for many reasons but mostly due to heavy third party SDKs. The problem with this is that even if we're not calling that specific procedure we still load ALL the router dependencies when calling any procedure. This impacts performance and cold boots significantly. Describe the solution you'd like to see Splitting big tRPC routers into lazy loadable chunks could help loading only what is needed when a procedure is called. I would imagine some pseudo code like this: Describe alternate solutions Other aternatives involve moving all the procedure code into a separate file a use imports for that as done in here. Also lazy loading only third party libraries (like Stripe, Google, etc.) seems to help. But it would be a much nicer DX being able to simply lazy load full routers and support it natively. Additional information _No response_ ๐จโ๐งโ๐ฆ Contributing - [X] ๐โโ๏ธ Yes, I'd be down to file a PR implementing this feature! <sub>TRP-19</sub>
Unverified for your environment
Select your OS to check compatibility.
1 Fix
Implement Lazy Loading for tRPC Routers
The current implementation of tRPC routers loads all dependencies at once, regardless of whether specific procedures are called. This results in increased load times and performance issues, especially when third-party SDKs are involved.
Awaiting Verification
Be the first to verify this fix
- 1
Refactor Router Structure
Split the existing tRPC router into smaller, modular routers that can be lazy-loaded. Each module should contain related procedures and dependencies.
typescriptexport const userRouter = createRouter().query('getUser', { resolve: () => { /* user fetching logic */ } }); export const orderRouter = createRouter().query('getOrder', { resolve: () => { /* order fetching logic */ } }); - 2
Implement Dynamic Import for Routers
Utilize dynamic imports to load the routers only when needed. This can be achieved using `import()` syntax within the procedure resolver.
typescriptconst getUser = async () => { const { userRouter } = await import('./routers/userRouter'); return userRouter.getUser(); }; - 3
Update tRPC Configuration
Modify the tRPC server configuration to support lazy loading of routers. Ensure that the main router can dynamically include the necessary modules based on incoming requests.
typescriptconst appRouter = createRouter().merge('user.', userRouter).merge('order.', orderRouter); - 4
Test Lazy Loading Implementation
Create unit tests to verify that the routers are loaded only when their procedures are called. Measure the performance before and after the implementation.
typescriptdescribe('Lazy Loading Routers', () => { it('should load userRouter only when getUser is called', async () => { const userRouter = await import('./routers/userRouter'); expect(userRouter).toBeDefined(); }); });
Validation
Confirm that the application loads faster and that only the necessary routers are loaded when specific procedures are called. Use performance profiling tools to measure improvements.
Sign in to verify this fix
Environment
Submitted by
Alex Chen
2450 rep