Routa
Routa is a schema-first, OpenAPI-aware REST framework for new TypeScript APIs. Choose your entry point based on whether you want a generated starter, need to add Routa to an existing TypeScript API, or already have an OpenAPI contract.
Options
Section titled “Options”Start From a Generated Project
Section titled “Start From a Generated Project”Use the scaffolder when you want the fastest path to a working Routa application:
npm create routa-ts@latestpnpm create routa-ts@latestyarn create routa-tsbun create routa-ts@latestYou receive a status route, tests, configuration, and committed .routa/ metadata. The
tradeoff is adopting Routa’s generated project shape before you have chosen each file.
Add Routa to an Existing API
Section titled “Add Routa to an Existing API”Follow Installation when you already have a TypeScript codebase and want to migrate one HTTP boundary at a time. You keep control of the surrounding application, but you must add the scripts, configuration entry point, and generated metadata yourself.
Start From OpenAPI
Section titled “Start From OpenAPI”Use Scaffold from OpenAPI when a reviewed OpenAPI document is the starting contract. Routa generates the first source representation and a baseline; after that import, route files become the source of truth and regeneration must be previewed.
What Routa Does
Section titled “What Routa Does”Routes are filesystem-backed. Folders map to URL segments, and each route.ts file owns
every method for that path.
import { createRoute, createRouteRoot } from "@routa-ts/core";import { CreateUserSchema, UserSchema } from "./schemas.js";import * as users from "../../services/users.js";
const route = createRouteRoot("/users");
export default route({ post: createRoute({ input: { body: CreateUserSchema, }, responses: { success: { status: 201, schema: UserSchema, }, }, run: async ({ input }) => { return { type: "success", data: await users.createUser(input.body) }; }, }),});input describes what the request must contain. Routa parses params, query,
headers, cookies, and body through those Zod schemas before the handler runs, so
input.body is already validated and typed.
responses is a map of named outcomes to a status and a schema. The handler returns one
of those names with its data. Returning an undeclared name is a type error, and returning
data that does not match the schema is caught at runtime before it reaches the client.
Everything else is derived. The CLI reads these files to generate route metadata, produce OpenAPI, and check that the contract has not drifted from its committed baseline.
Consequences
Section titled “Consequences”- One route contract drives TypeScript types, runtime validation, generated metadata, and OpenAPI, so contract changes appear in several reviewable outputs.
- Filesystem paths and
createRouteRoot(path)must agree; moving a route is an API change. - Business logic does not belong in
run. Routa owns routing, validation, middleware context, typed responses, and OpenAPI, while services, domain models, and persistence stay application-owned. .routa/is committed source-derived state, not a disposable build artifact.