Routa

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@latest

Side by side

Untyped handler vs contracted route

Same job. One hopes the status codes match the docs. The other declares the contract in source.

without Routavibes
app.post("/users", async (c) => {
  const body = await c.req.json();
  // validate… somewhere?
  const user = await create(body);
  return c.json(user, 201);
});
with Routacontract
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.