Filesystem routes with contracts, not vibes
A schematic of the API: routes as edges, schemas as nodes, OpenAPI as projection. Schema-first REST for TypeScript — Zod contracts on a Hono runtime.
npm create routa-ts@latestSide by side
Untyped handler vs contracted route
Same job. One hopes the status codes match the docs. The other declares the contract in source.
app.post("/users", async (c) => {
const body = await c.req.json();
// validate… somewhere?
const user = await create(body);
return c.json(user, 201);
});const route = createRouteRoot("/users");
export default route({
post: createRoute({
input: { body: CreateUserSchema },
responses: {
success: { status: 201, schema: UserSchema },
},
run: async ({ input }) => ({
type: "success",
data: await users.createUser(input.body),
}),
}),
});- Route = contract
Path, methods, I/O, and outcomes in one file.
- Lattice composition
Middleware and schemas form a typed graph you can check.
- OpenAPI peer
Projection of the same lattice — scaffold or emit.
- CLI lifecycle
check, build, start — in that order.
- Hono
- Zod
- OpenAPI
- TypeScript
v0— intentionally narrow. Schema-first REST, not a fullstack meta-framework.
Map the docs
From first route to OpenAPI lockstep.