Documentation Index Fetch the complete documentation index at: https://mintlify.com/lukeautry/tsoa/llms.txt
Use this file to discover all available pages before exploring further.
tsoa supports multiple OpenAPI (formerly Swagger) specification versions. Understanding the differences and how to configure them is important for API documentation and client generation.
Supported Versions
tsoa supports three major OpenAPI versions:
OpenAPI 3.1 (Latest) - Released 2021, JSON Schema compatible
OpenAPI 3.0 - Released 2017, widely adopted
OpenAPI 2.0 (Swagger) - Original specification, deprecated but still supported
Configuring Spec Version
Set the OpenAPI version in your tsoa.json:
OpenAPI 3.1
OpenAPI 3.0
Swagger 2.0
{
"spec" : {
"outputDirectory" : "./build" ,
"specVersion" : 3.1
}
}
{
"spec" : {
"outputDirectory" : "./build" ,
"specVersion" : 3
}
}
{
"spec" : {
"outputDirectory" : "./build" ,
"specVersion" : 2
}
}
Version Comparison
OpenAPI 3.1 vs 3.0
openapi : 3.1.0
info :
title : My API
version : 1.0.0
components :
schemas :
User :
type : object
properties :
id :
type : integer
name :
type : string
email :
type : [ string , "null" ] # Nullable in 3.1
required :
- id
- name
Key Differences
Feature OpenAPI 3.1 OpenAPI 3.0 Swagger 2.0 JSON Schema Full compatibility Partial Extended subset Nullable type: [string, "null"]nullable: truex-nullable: trueExamples examplesexampleexampleWebhooks ✅ Supported ❌ Not supported ❌ Not supported const✅ Supported ❌ Not supported ❌ Not supported $schema✅ Allowed ❌ Not allowed ❌ Not allowed
OpenAPI 3.1 Features
Full JSON Schema Support
OpenAPI 3.1 is fully compatible with JSON Schema 2020-12:
interface User {
id : number ;
/**
* User's email address
* @format email
* @pattern ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
*/
email : string ;
/**
* User's age
* @minimum 18
* @maximum 120
*/
age : number ;
/**
* User's role
* @default " user "
*/
role : 'admin' | 'user' | 'guest' ;
}
Nullable Types
In OpenAPI 3.1, use union types for nullable:
interface Product {
id : number ;
name : string ;
description : string | null ; // Can be string or null
price ?: number ; // Optional (can be undefined)
}
Generated spec:
Product :
type : object
properties :
id :
type : integer
name :
type : string
description :
type :
- string
- "null"
price :
type : number
required :
- id
- name
- description
Const Values
interface Config {
/**
* @const "v1"
*/
version : string ;
/**
* @const 443
*/
port : number ;
}
OpenAPI 3.0 Features
Request Bodies
Explicit request body objects:
import { Controller , Post , Route , Body } from 'tsoa' ;
interface CreateUserRequest {
name : string ;
email : string ;
}
@ Route ( 'users' )
export class UserController extends Controller {
/**
* Create a new user
* @param requestBody User creation data
*/
@ Post ()
public async createUser (
@ Body () requestBody : CreateUserRequest
) : Promise < User > {
return createUser ( requestBody );
}
}
Generated spec:
paths :
/users :
post :
requestBody :
required : true
content :
application/json :
schema :
$ref : '#/components/schemas/CreateUserRequest'
responses :
'200' :
description : Ok
content :
application/json :
schema :
$ref : '#/components/schemas/User'
Multiple Response Types
import { Controller , Get , Route , Response } from 'tsoa' ;
interface ErrorResponse {
message : string ;
code : string ;
}
@ Route ( 'users' )
export class UserController extends Controller {
/**
* Get user by ID
*/
@ Get ( '{id}' )
@ Response < ErrorResponse >( 404 , 'Not Found' )
@ Response < ErrorResponse >( 500 , 'Internal Server Error' )
public async getUser ( id : number ) : Promise < User > {
return getUser ( id );
}
}
Security Schemes
{
"spec" : {
"securityDefinitions" : {
"jwt" : {
"type" : "http" ,
"scheme" : "bearer" ,
"bearerFormat" : "JWT"
},
"api_key" : {
"type" : "apiKey" ,
"name" : "X-API-Key" ,
"in" : "header"
},
"oauth2" : {
"type" : "oauth2" ,
"flows" : {
"authorizationCode" : {
"authorizationUrl" : "https://example.com/oauth/authorize" ,
"tokenUrl" : "https://example.com/oauth/token" ,
"scopes" : {
"read:users" : "Read user data" ,
"write:users" : "Modify user data"
}
}
}
}
}
}
}
Swagger 2.0 Support
While deprecated, Swagger 2.0 is still supported for legacy systems:
{
"spec" : {
"outputDirectory" : "./build" ,
"specVersion" : 2 ,
"host" : "api.example.com" ,
"basePath" : "/v1" ,
"schemes" : [ "https" ],
"securityDefinitions" : {
"api_key" : {
"type" : "apiKey" ,
"name" : "api_key" ,
"in" : "header"
}
}
}
}
Swagger 2.0 Limitations
Swagger 2.0 has several limitations:
No oneOf, anyOf, or allOf support
Limited nullable type support
No cookie parameters
No request body content types
No callback support
Migrating Between Versions
From 2.0 to 3.0
Update Configuration
{
"spec" : {
"specVersion" : 3 // Changed from 2
}
}
Update Security Definitions
// Before (Swagger 2.0)
{
"securityDefinitions" : {
"Bearer" : {
"type" : "apiKey" ,
"name" : "Authorization" ,
"in" : "header"
}
}
}
// After (OpenAPI 3.0)
{
"securityDefinitions" : {
"Bearer" : {
"type" : "http" ,
"scheme" : "bearer" ,
"bearerFormat" : "JWT"
}
}
}
Update File Uploads
File upload parameters change in 3.0: // Works in both versions
@ Post ( 'upload' )
public async upload (
@ UploadedFile () file : Express . Multer . File
): Promise < any > {
return { filename : file . originalname };
}
From 3.0 to 3.1
Update Version
{
"spec" : {
"specVersion" : 3.1 // Changed from 3
}
}
Update Nullable Types
// Before (3.0 style)
interface User {
/**
* @nullable
*/
email : string ;
}
// After (3.1 style)
interface User {
email : string | null ;
}
Spec Customization
{
"spec" : {
"outputDirectory" : "./build" ,
"specVersion" : 3.1 ,
"name" : "My API" ,
"version" : "1.0.0" ,
"description" : "API for managing users and products" ,
"license" : "MIT" ,
"contact" : {
"name" : "API Support" ,
"email" : "support@example.com" ,
"url" : "https://example.com/support"
}
}
}
Servers
Define multiple server environments:
{
"spec" : {
"servers" : [
{
"url" : "https://api.example.com/v1" ,
"description" : "Production server"
},
{
"url" : "https://staging-api.example.com/v1" ,
"description" : "Staging server"
},
{
"url" : "http://localhost:3000/v1" ,
"description" : "Development server"
}
]
}
}
Organize endpoints by tags:
{
"spec" : {
"tags" : [
{
"name" : "Users" ,
"description" : "User management endpoints"
},
{
"name" : "Products" ,
"description" : "Product catalog endpoints"
}
]
}
}
External Documentation
{
"spec" : {
"externalDocs" : {
"description" : "Full API Documentation" ,
"url" : "https://docs.example.com"
}
}
}
Generate both JSON and YAML:
{
"spec" : {
"outputDirectory" : "./build" ,
"specVersion" : 3.1 ,
"yaml" : true // Generate YAML in addition to JSON
}
}
This creates both:
build/swagger.json
build/swagger.yaml
Viewing Specifications
Swagger UI
Serve your spec with Swagger UI:
import express from 'express' ;
import swaggerUi from 'swagger-ui-express' ;
import * as swaggerDocument from './build/swagger.json' ;
const app = express ();
app . use ( '/api-docs' , swaggerUi . serve , swaggerUi . setup ( swaggerDocument ));
app . listen ( 3000 );
Access at http://localhost:3000/api-docs
Redoc
Use Redoc for a cleaner documentation UI:
import express from 'express' ;
import { redoc } from 'redoc-express' ;
const app = express ();
app . get ( '/docs' , redoc ({
title: 'API Documentation' ,
specUrl: '/swagger.json'
}));
app . get ( '/swagger.json' , ( req , res ) => {
res . json ( require ( './build/swagger.json' ));
});
app . listen ( 3000 );
Client Generation
Use your OpenAPI spec to generate clients:
OpenAPI Generator
# Install
npm install -g @openapitools/openapi-generator-cli
# Generate TypeScript client
openapi-generator-cli generate \
-i build/swagger.json \
-g typescript-axios \
-o client/
# Generate Python client
openapi-generator-cli generate \
-i build/swagger.json \
-g python \
-o client-python/
Swagger Codegen
npx @apidevtools/swagger-cli bundle build/swagger.json \
--outfile build/swagger-bundled.json \
--type json
Best Practices
Use Latest Stable Version
Use OpenAPI 3.0 or 3.1 for new projects. Only use Swagger 2.0 if required for legacy tooling.
Include version in URL or headers, and maintain separate specs for each major version.
Use JSDoc comments for descriptions, examples, and constraints.
Use tools like Spectral or swagger-cli to validate your spec: npx @stoplight/spectral-cli lint build/swagger.json
Commit generated specs to track API changes over time.
Troubleshooting
Spec Generation Fails
Check TypeScript compilation
Verify tsoa configuration
Check for syntax errors in decorators
Invalid Spec
Validate your spec:
npx swagger-cli validate build/swagger.json
Missing Types
Ensure all referenced types are exported:
// Export all types used in controllers
export interface User { ... }
export interface CreateUserRequest { ... }
Next Steps
Custom Templates Customize route generation templates
API Documentation Learn about API documentation