{"id":12201,"library":"tsoa","title":"tsoa: TypeScript OpenAPI Framework","description":"tsoa is a powerful TypeScript-first framework designed to streamline the creation of REST APIs by automatically generating OpenAPI (formerly Swagger) documentation and client SDKs directly from your existing TypeScript code. It employs decorators and standard TypeScript types to define API routes, request bodies, query parameters, and response structures. A critical step involves a code generation phase that produces both the OpenAPI specification and the concrete route registration logic for popular Node.js frameworks such as Express, Hapi, and Koa. The project exhibits an active development cycle, with consistent minor releases every few months, and has recently released a v7 alpha that introduces support for OpenAPI 3.1.0 and updated Node.js version requirements. Its key differentiator is the \"code-first\" approach, eliminating the need to manually maintain separate OpenAPI definitions by deriving them directly from the TypeScript source, ensuring strong type consistency between API implementation and documentation. The current stable version is v6.6.0.","status":"active","version":"7.0.0-alpha.0","language":"javascript","source_language":"en","source_url":"https://github.com/lukeautry/tsoa","tags":["javascript","typescript","openapi","swagger","server","node","node.js","codegen","generation"],"install":[{"cmd":"npm install tsoa","lang":"bash","label":"npm"},{"cmd":"yarn add tsoa","lang":"bash","label":"yarn"},{"cmd":"pnpm add tsoa","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required for compiling TypeScript controllers and generating metadata. It's a fundamental build-time dependency.","package":"typescript","optional":false},{"reason":"Commonly used web framework for which tsoa generates routes and expects runtime integration. Often installed alongside tsoa.","package":"express","optional":true},{"reason":"Required for handling file uploads via @UploadedFile and @UploadedFiles decorators.","package":"multer","optional":true},{"reason":"Required by generated routes file, especially important for pnpm users due to its symlinked node_modules structure.","package":"@tsoa/runtime","optional":false}],"imports":[{"note":"Most decorators and the base Controller class are imported directly from the 'tsoa' package. While `@tsoa/runtime` exists, `tsoa` is the primary entry point for decorators.","wrong":"import { Controller } from '@tsoa/runtime'","symbol":"Controller","correct":"import { Controller, Route, Get, Post, Body, Path, Query } from 'tsoa'"},{"note":"RegisterRoutes is a function generated by the `tsoa routes` CLI command. Its path is relative to your compiled application entry file and depends on the `routesDir` setting in `tsoa.json`. Common mistake is to try and import it directly from 'tsoa' or use an incorrect relative path.","wrong":"import { RegisterRoutes } from 'tsoa'","symbol":"RegisterRoutes","correct":"import { RegisterRoutes } from '../build/routes'"},{"note":"tsoa's primary functions are accessed via CLI commands `tsoa spec` to generate OpenAPI definition and `tsoa routes` to generate route handlers. These commands are typically run as part of a build script.","wrong":"tsoa generate","symbol":"tsoa CLI","correct":"npx tsoa spec && npx tsoa routes"}],"quickstart":{"code":"// tsoa.json (in project root)\n// {\n//   \"entryFile\": \"src/app.ts\",\n//   \"controllers\": [\"src/controllers/**/*.ts\"],\n//   \"spec\": {\n//     \"outputDirectory\": \"build\",\n//     \"specVersion\": 3,\n//     \"yaml\": false\n//   },\n//   \"routes\": {\n//     \"routesDir\": \"build\"\n//   }\n// }\n\n// src/controllers/usersController.ts\nimport { Controller, Route, Get, Path, Post, Body, SuccessResponse } from 'tsoa';\n\ninterface User {\n  id: number;\n  name: string;\n}\n\ninterface CreateUserRequest {\n  name: string;\n}\n\n@Route('users')\nexport class UsersController extends Controller {\n  private users: User[] = [{ id: 1, name: 'Alice' }];\n\n  @Get('{userId}')\n  public async getUser(@Path() userId: number): Promise<User | undefined> {\n    return this.users.find(u => u.id === userId);\n  }\n\n  @SuccessResponse(201, 'Created') // Set HTTP status code for success\n  @Post()\n  public async createUser(@Body() requestBody: CreateUserRequest): Promise<User> {\n    const newUser: User = {\n      id: this.users.length + 1,\n      name: requestBody.name,\n    };\n    this.users.push(newUser);\n    return newUser;\n  }\n}\n\n// src/app.ts (your Express server entry file)\nimport express from 'express';\nimport { RegisterRoutes } from '../build/routes'; // Path relative to app.ts's compiled output\nimport * as swaggerUi from 'swagger-ui-express';\nimport * as path from 'path';\n\nconst app = express();\napp.use(express.json()); // For parsing application/json\napp.use(express.urlencoded({ extended: true })); // For parsing application/x-www-form-urlencoded\n\nRegisterRoutes(app); // Register the tsoa-generated routes\n\n// Serve OpenAPI UI\ntry {\n  // Ensure 'swagger.json' is generated by `tsoa spec` in your build directory\n  const swaggerDocument = require(path.resolve(__dirname, '../build/swagger.json'));\n  app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));\n} catch (error) {\n  console.error('Failed to load swagger.json. Did you run `tsoa spec`?', error);\n}\n\n// Generic error handler middleware\napp.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {\n  console.error(err);\n  const status = err.status || 500;\n  const message = err.message || 'An unexpected error occurred.';\n  res.status(status).json({ message });\n});\n\nconst port = process.env.PORT || 3000;\napp.listen(port, () => {\n  console.log(`Server running on http://localhost:${port}`);\n  console.log(`API docs available at http://localhost:${port}/docs`);\n});\n\n// To run this application:\n// 1. Install dependencies: `npm install express tsoa swagger-ui-express @types/express @types/swagger-ui-express typescript ts-node @tsoa/runtime`\n// 2. Configure `tsconfig.json` with: `\"experimentalDecorators\": true`, `\"emitDecoratorMetadata\": true` (recommended).\n// 3. Add scripts to `package.json`: `\"tsoa:gen\": \"tsoa spec && tsoa routes\", \"build\": \"npm run tsoa:gen && tsc\", \"start\": \"npm run build && node build/app.js\"`\n// 4. Run `npm start` to build and launch the server.","lang":"typescript","description":"This quickstart demonstrates setting up a basic tsoa-powered Express API, including defining a controller with decorators, registering generated routes, and serving the OpenAPI documentation using swagger-ui-express. It highlights the compile-time code generation steps necessary for tsoa applications."},"warnings":[{"fix":"Ensure your Node.js environment is updated to a supported version (e.g., Node.js 22, 24, or 25 for tsoa v7). For v6, ensure Node.js >= 18.0.0.","message":"tsoa v7.0.0-alpha.0 (and newer) has updated its officially supported Node.js versions. While v6 requires Node.js >= 18.0.0, v7 specifically tests against and officially supports Node.js versions 22, 24, and 25. Using older Node.js versions with v7 might lead to unexpected behavior or failures.","severity":"breaking","affected_versions":">=7.0.0-alpha.0"},{"fix":"In your `tsoa.json`, set `\"spec\": { \"specVersion\": 3 }` (or `2` for OpenAPI 2.0/Swagger) to explicitly specify the desired OpenAPI version.","message":"Since v7.0.0-alpha.0, OpenAPI 3.1.0 is the default output format for the generated specification. If your tooling (e.g., client SDK generators, API gateways) does not yet support OpenAPI 3.1.0, you will need to explicitly configure tsoa to output an older version (e.g., 3.0.0) in your `tsoa.json` file.","severity":"breaking","affected_versions":">=7.0.0-alpha.0"},{"fix":"Integrate `tsoa spec && tsoa routes` into your build pipeline, typically as part of your `package.json` scripts (e.g., `\"build\": \"npm run tsoa:gen && tsc\", \"tsoa:gen\": \"tsoa spec && tsoa routes\"`).","message":"tsoa relies heavily on a code generation step (`tsoa spec` and `tsoa routes`) which *must* be executed before your application is compiled and run. Forgetting this step will result in missing route definitions and OpenAPI specifications, leading to runtime errors like 'Cannot find module ../build/routes'.","severity":"gotcha","affected_versions":">=3.0.0"},{"fix":"For basic file uploads, ensure `multer` and `@types/multer` are installed. For complex scenarios, consider using a custom Multer instance directly within your controller method, passing the Express `Request` object using the `@Request()` decorator, and then manually invoking Multer middleware.","message":"Handling file uploads with `@UploadedFile()` and `@UploadedFiles()` decorators often requires `multer`. Earlier versions (pre-v6.4.0) had less flexibility, sometimes leading to conflicts or issues with custom Multer configurations. While `tsoa.json` can configure `multerOptions`, for advanced use cases (e.g., custom storage engines like `multer-s3`), directly integrating Multer in the controller might be necessary.","severity":"gotcha","affected_versions":">=3.0.0"},{"fix":"Add or ensure the following in your `tsconfig.json` under `compilerOptions`: `\"experimentalDecorators\": true` and `\"emitDecoratorMetadata\": true`.","message":"tsoa requires `experimentalDecorators` and `emitDecoratorMetadata` to be enabled in your `tsconfig.json`. Without these TypeScript compiler options, decorators like `@Route`, `@Get`, and `@Body` will not function correctly, leading to compilation errors or unexpected runtime behavior where routes are not registered.","severity":"gotcha","affected_versions":">=3.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Run `npx tsoa routes` as part of your build process. Verify that `routesDir` in `tsoa.json` matches the intended output directory, and that the import path in your `app.ts` is correct relative to its compiled location.","cause":"The `tsoa routes` command has not been executed, or the `routesDir` in `tsoa.json` is incorrect, preventing the generation of the `routes.ts` file.","error":"TS2307: Cannot find module '../build/routes' or its corresponding type declarations."},{"fix":"Check the `controllerPathGlobs` array in your `tsoa.json` to ensure it correctly points to your controller files (e.g., `\"src/controllers/**/*.ts\"`). Also, confirm that your controller classes have the `@Route()` decorator.","cause":"tsoa could not find any controller files matching the `controllerPathGlobs` specified in `tsoa.json`, or no classes within those files were decorated with `@Route()`.","error":"Error: No routes were found! Have you configured your tsoa.json correctly?"},{"fix":"For JSON payloads, ensure `app.use(express.json())` is called early in your Express application setup. For URL-encoded data, use `app.use(express.urlencoded({ extended: true }))`. Use appropriate tsoa decorators like `@Body()`, `@BodyProp()`, or `@FormField()` for different request body types.","cause":"The Express (or other framework) application is not configured with middleware to parse incoming request bodies (e.g., JSON or URL-encoded data), or the wrong `@Body` decorator is used for the content type.","error":"TypeError: Cannot read properties of undefined (reading 'body')"},{"fix":"Ensure the string argument passed to `@UploadedFile('fieldName')` or `@UploadedFiles('fieldName')` exactly matches the `name` attribute of the file input in your HTML form or the key in your `FormData` object. If using custom Multer, ensure it's configured correctly.","cause":"A mismatch exists between the field name used in the client's form data upload and the field name expected by the `@UploadedFile()` or `@UploadedFiles()` decorator in the controller, or Multer isn't correctly initialized/passed.","error":"MulterError: Unexpected field"},{"fix":"Remove the explicit `compilerOptions` field from `tsoa.json` and let tsoa infer them from your main `tsconfig.json`. If custom options are strictly needed, ensure they are provided in a correctly structured object that `ts.createProgram` expects, or consider passing a `compilerOptions` object programmatically to `generateSpec` and `generateRoutes` functions if using the API directly.","cause":"This error can occur in tsoa v6.5.0+ when `compilerOptions` are explicitly passed in `tsoa.json` directly as a string or in an incorrect format that TypeScript's `createProgram` cannot parse. This often happens with shared `tsconfig` files or non-standard configurations.","error":"Error: target is a string value; tsconfig JSON must be parsed with parseJsonSourceFileConfigFileContent or getParsedCommandLineOfConfigFile before passing to createProgram"}],"ecosystem":"npm"}