Incrementally adoptable RPC-like client and server helpers for a magical end to end typed experience 🪄
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.
- End-to-end type safety 🛟
- RPC-like client side API ⚡️
- Small Bundle Size 📉
- No Code Generation 🏃♀️
- Zod support for runtime validation 🔒
- Full optional OpenAPI integration 📝
👉 Start reading the official Quickstart Guide 👈
Easily define your API contract somewhere shared
constcontract=c.router({getPosts: {method: 'GET',path: '/posts',query: z.object({skip: z.number(),take: z.number(),}),// <-- Zod schemaresponses: {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:
constrouter=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:
constresult=awaitclient.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.
👉 Start reading the official Quickstart Guide 👈
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.
