Skip to main content
Version: 10.x

Merging Routers

Writing all API-code in your code in the same file is not a great idea. It's easy to merge routers with other routers.

Thanks to TypeScript 4.1 template literal types we can also prefix the procedures without breaking typesafety.

Merging with child routers

server.ts
ts
// @filename: routers/_app.ts
import { t } from '../trpc';
import { z } from 'zod';
 
import { userRouter } from './user';
import { postRouter } from './post';
 
const appRouter = t.router({
user: userRouter, // put procedures under "user" namespace
post: postRouter, // put procedures under "post" namespace
});
 
export type AppRouter = typeof appRouter;
 
 
// @filename: routers/post.ts
import { t } from '../trpc';
import { z } from 'zod';
export const postRouter = t.router({
create: t.procedure
.input(
z.object({
title: z.string(),
}),
)
.mutation(({ input }) => {
(parameter) input: { title: string; }
// [...]
}),
list: t.procedure.query(() => {
// ...
return [];
}),
});
 
// @filename: routers/user.ts
import { t } from '../trpc';
import { z } from 'zod';
export const userRouter = t.router({
list: t.procedure.query(() => {
// [..]
return [];
}),
});
 
server.ts
ts
// @filename: routers/_app.ts
import { t } from '../trpc';
import { z } from 'zod';
 
import { userRouter } from './user';
import { postRouter } from './post';
 
const appRouter = t.router({
user: userRouter, // put procedures under "user" namespace
post: postRouter, // put procedures under "post" namespace
});
 
export type AppRouter = typeof appRouter;
 
 
// @filename: routers/post.ts
import { t } from '../trpc';
import { z } from 'zod';
export const postRouter = t.router({
create: t.procedure
.input(
z.object({
title: z.string(),
}),
)
.mutation(({ input }) => {
(parameter) input: { title: string; }
// [...]
}),
list: t.procedure.query(() => {
// ...
return [];
}),
});
 
// @filename: routers/user.ts
import { t } from '../trpc';
import { z } from 'zod';
export const userRouter = t.router({
list: t.procedure.query(() => {
// [..]
return [];
}),
});
 

Merging with t.mergeRouters

If you prefer having all procedures flat in your router, you can instead use t.mergeRouters

server.ts
ts
// @filename: routers/_app.ts
import { t } from '../trpc';
import { z } from 'zod';
 
import { userRouter } from './user';
import { postRouter } from './post';
 
const appRouter = t.mergeRouters(userRouter, postRouter)
 
export type AppRouter = typeof appRouter;
 
// @filename: routers/post.ts
import { t } from '../trpc';
import { z } from 'zod';
export const postRouter = t.router({
postCreate: t.procedure
.input(
z.object({
title: z.string(),
}),
)
.mutation(({ input }) => {
(parameter) input: { title: string; }
// [...]
}),
postList: t.procedure.query(() => {
// ...
return [];
}),
});
 
 
// @filename: routers/user.ts
import { t } from '../trpc';
import { z } from 'zod';
export const userRouter = t.router({
userList: t.procedure.query(() => {
// [..]
return [];
}),
});
 
server.ts
ts
// @filename: routers/_app.ts
import { t } from '../trpc';
import { z } from 'zod';
 
import { userRouter } from './user';
import { postRouter } from './post';
 
const appRouter = t.mergeRouters(userRouter, postRouter)
 
export type AppRouter = typeof appRouter;
 
// @filename: routers/post.ts
import { t } from '../trpc';
import { z } from 'zod';
export const postRouter = t.router({
postCreate: t.procedure
.input(
z.object({
title: z.string(),
}),
)
.mutation(({ input }) => {
(parameter) input: { title: string; }
// [...]
}),
postList: t.procedure.query(() => {
// ...
return [];
}),
});
 
 
// @filename: routers/user.ts
import { t } from '../trpc';
import { z } from 'zod';
export const userRouter = t.router({
userList: t.procedure.query(() => {
// [..]
return [];
}),
});