Incrementally adoptable RPC-like client and server helpers for a magical end to end typed experience 🪄
Join us on Discord for help, feedback, and discussions!
ts-rest offers a simple way to define a contract for your API, which can be both consumed and implemented by your application, giving you end to end type safety without the hassle or code generation.
Easily define your API contract somewhere shared
const contract = c.router({
getPosts: {
method: 'GET',
path: '/posts',
query: z.object({
skip: z.number(),
take: z.number(),
}), // <-- Zod schema
responses: {
200: c.type<Post[]>(), // <-- OR normal TS types
},
headers: z.object({
'x-pagination-page': z.coerce.number().optional(),
}),
},
});
Fulfill the contract on your server, with a type-safe router:
const router = s.router(contract, {
getPosts: async ({ params: { id } }) => {
return {
status: 200,
body: prisma.post.findUnique({ where: { id } }),
};
},
});
Consume the api on the client with a RPC-like interface:
const result = await client.getPosts({
headers: { 'x-pagination-page': 1 },
query: { skip: 0, take: 10 },
// ^-- Fully typed!
});
Create a contract, implement it on your server then consume it in your client. Incrementally adopt, trial it with your team, then get shipping faster.
MASSIVE Thanks to all of these wonderful people (emoji key), who have helped make ts-rest possible:
Since our first commit in 2022 we've been growing steadily. We're proud of our progress and we're excited about the future.
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=ts-rest/ts-rest&type=Timeline" />
Join us on Discord for help, feedback, and discussions!
<a href="https://vercel.com/?utm_source=ts-rest&utm_campaign=oss" target="_blank" rel="noreferrer"
<img src="https://ts-rest.com/img/powered-by-vercel.svg" alt="Powered by Vercel" height="40" />
$ claude mcp add ts-rest \
-- python -m otcore.mcp_server <graph>