tsoa is configured through a configuration file that defines how specifications and routes are generated. The configuration file can be in JSON, YAML, or JavaScript format.
Configuration File
By default, tsoa looks for tsoa.json in your project root. You can use alternative formats or locations:
tsoa.json
tsoa.yaml
tsoa.js
{
"entryFile" : "src/app.ts" ,
"noImplicitAdditionalProperties" : "throw-on-extras" ,
"spec" : {
"outputDirectory" : "dist" ,
"specVersion" : 3
},
"routes" : {
"routesDir" : "src" ,
"middleware" : "express"
}
}
Use JavaScript format (tsoa.js) when you need dynamic configuration or want to compute values at runtime.
Configuration Structure
The configuration file has four main sections:
interface Config {
entryFile : string ; // Entry point to your API
spec : SpecConfig ; // OpenAPI spec generation
routes : RoutesConfig ; // Route handler generation
// Optional settings
controllerPathGlobs ?: string []; // Alternative to entryFile
noImplicitAdditionalProperties ?: string ;
compilerOptions ?: Record < string , unknown >;
ignore ?: string [];
multerOpts ?: MulterOptions ;
defaultNumberType ?: string ;
}
Entry Point Configuration
You must specify how tsoa finds your controllers using either entryFile or controllerPathGlobs:
Using entryFile
Points to a file that imports all your controllers:
{
"entryFile" : "src/app.ts"
}
import './controllers/usersController' ;
import './controllers/productsController' ;
import './controllers/ordersController' ;
// tsoa will scan all imported controllers
The entry file doesn’t need to contain any tsoa-specific code. It just needs to import your controllers directly or indirectly.
Using controllerPathGlobs
Use glob patterns to directly specify controller files:
{
"controllerPathGlobs" : [
"src/controllers/**/*Controller.ts" ,
"src/modules/**/controllers/*.ts"
]
}
entryFile Pros:
Single source of truth
Respects your imports
Works with any structure
Cons:
Must import all controllers
Slower for large projects
controllerPathGlobs Pros:
Faster generation
No import required
Explicit file selection
Cons:
Must maintain glob patterns
Could pick up unwanted files
Global Options
noImplicitAdditionalProperties
Controls how tsoa handles extra properties in request bodies:
noImplicitAdditionalProperties
"ignore" - Allow extra properties (default)
"silently-remove-extras" - Remove extra properties without error
"throw-on-extras" - Reject requests with extra properties
{
"noImplicitAdditionalProperties" : "throw-on-extras"
}
Controller
Request (ignore)
Request (silently-remove-extras)
Request (throw-on-extras)
interface CreateUserRequest {
name : string ;
email : string ;
}
@ Post ( 'users' )
public async createUser (@ Body () body : CreateUserRequest ) {
// ...
}
Using "throw-on-extras" provides the strictest validation but may break clients sending additional fields. Start with "silently-remove-extras" for a safer migration path.
ignore
Directories to ignore when scanning TypeScript files:
{
"ignore" : [
"**/node_modules/**" ,
"**/test/**" ,
"**/dist/**"
]
}
Ignoring unnecessary directories significantly improves generation speed for large projects.
compilerOptions
Override TypeScript compiler options during generation:
{
"compilerOptions" : {
"target" : "ES2020" ,
"module" : "commonjs" ,
"esModuleInterop" : true ,
"skipLibCheck" : true
}
}
These options are merged with your tsconfig.json. Use this when generation needs different settings than your build.
defaultNumberType
How TypeScript number type maps to OpenAPI:
{
"defaultNumberType" : "double"
}
"double" - 64-bit floating point
"float" - 32-bit floating point
"integer" - 32-bit integer
"long" - 64-bit integer
interface Product {
price : number ; // Uses defaultNumberType
quantity : number ; // Uses defaultNumberType
// Override with JSDoc tags:
/** @isInt */
stock : number ; // Always integer
/** @isFloat */
rating : number ; // Always float
}
Spec Configuration
Controls OpenAPI specification generation:
{
"spec" : {
"outputDirectory" : "dist" ,
"specVersion" : 3 ,
"specFileBaseName" : "swagger" ,
"host" : "api.example.com" ,
"basePath" : "/v1" ,
"schemes" : [ "https" ],
"yaml" : true
}
}
Required Options
Directory where the OpenAPI spec file will be written. { "spec" : { "outputDirectory" : "dist/docs" } }
OpenAPI version to generate: 2, 3, or 3.1 { "spec" : { "specVersion" : 3 } }
Output in YAML format instead of JSON. { "spec" : { "yaml" : true } }
Base name of the output file (without extension). { "spec" : { "specFileBaseName" : "openapi" } }
Generates openapi.json or openapi.yaml
By default, tsoa extracts these from package.json:
API name (defaults to package.json name)
API version (defaults to package.json version)
API description (defaults to package.json description)
API license (defaults to package.json license)
{
"spec" : {
"name" : "My API" ,
"version" : "2.0.0" ,
"description" : "A comprehensive API for..." ,
"license" : "MIT"
}
}
Server Configuration
{
"spec" : {
"specVersion" : 2 ,
"host" : "api.example.com" ,
"basePath" : "/v1" ,
"schemes" : [ "https" , "http" ]
}
}
Generates URLs like: https://api.example.com/v1/users {
"spec" : {
"specVersion" : 3 ,
"servers" : [
"https://api.example.com/v1" ,
"https://staging.example.com/v1"
]
}
}
Or with base path: {
"spec" : {
"basePath" : "/v1" ,
"servers" : [
"https://api.example.com" ,
"https://staging.example.com"
]
}
}
Advanced Spec Options
See the tsoa.json Reference for complete details on:
Security definitions
Contact information
Tags
Spec merging strategies
Operation ID templates
And more…
Routes Configuration
Controls route handler generation:
{
"routes" : {
"routesDir" : "src" ,
"middleware" : "express" ,
"routesFileName" : "routes.ts" ,
"basePath" : "/api" ,
"authenticationModule" : "./auth.ts" ,
"iocModule" : "./ioc.ts"
}
}
Required Options
Directory where routes file will be generated. { "routes" : { "routesDir" : "src/generated" } }
Middleware Selection
Web framework to generate routes for:
"express" - Express.js
"koa" - Koa.js
"hapi" - Hapi.js
{ "routes" : { "middleware" : "express" } }
import express from 'express' ;
import { RegisterRoutes } from './routes' ;
const app = express ();
app . use ( express . json ());
RegisterRoutes ( app );
app . listen ( 3000 );
Module Integration
routes.authenticationModule
Path to authentication handler module. { "routes" : { "authenticationModule" : "./auth/handler.ts" } }
Authentication module must export an expressAuthentication (or koaAuthentication/hapiAuthentication) function:
import { Request } from 'express' ;
export function expressAuthentication (
request : Request ,
securityName : string ,
scopes ?: string []
) : Promise < any > {
if ( securityName === 'jwt' ) {
const token = request . headers . authorization ?. split ( ' ' )[ 1 ];
return verifyJWT ( token , scopes );
}
throw new Error ( 'Unknown security scheme' );
}
Path to IoC container module (e.g., for InversifyJS). { "routes" : { "iocModule" : "./ioc/container.ts" } }
IoC module must export an iocContainer:
import { Container } from 'inversify' ;
import { UserService } from './services' ;
const iocContainer = new Container ();
iocContainer . bind < UserService >( UserService ). toSelf ();
export { iocContainer };
Additional Options
routes.routesFileName
string
default: "routes.ts"
Name of the generated routes file.
Base path prepended to all routes.
Generate imports with .js extensions for ES modules. { "routes" : { "esm" : true } }
Generates: import { Controller } from './controller.js'
Automatically coerce body parameters to expected types.
routes.noWriteIfUnchanged
Skip writing routes file if content hasn’t changed (useful for watch mode).
Example Configurations
Basic Express API
{
"entryFile" : "src/app.ts" ,
"noImplicitAdditionalProperties" : "silently-remove-extras" ,
"spec" : {
"outputDirectory" : "dist" ,
"specVersion" : 3 ,
"basePath" : "/api"
},
"routes" : {
"routesDir" : "src" ,
"middleware" : "express" ,
"basePath" : "/api"
}
}
Production API with Security
{
"entryFile" : "src/server.ts" ,
"noImplicitAdditionalProperties" : "throw-on-extras" ,
"ignore" : [ "**/node_modules/**" , "**/test/**" ],
"spec" : {
"outputDirectory" : "docs" ,
"specVersion" : 3 ,
"specFileBaseName" : "openapi" ,
"servers" : [ "https://api.example.com" ],
"basePath" : "/v1" ,
"securityDefinitions" : {
"jwt" : {
"type" : "http" ,
"scheme" : "bearer" ,
"bearerFormat" : "JWT"
},
"api_key" : {
"type" : "apiKey" ,
"name" : "X-API-Key" ,
"in" : "header"
}
}
},
"routes" : {
"routesDir" : "src/generated" ,
"routesFileName" : "routes.ts" ,
"middleware" : "express" ,
"basePath" : "/v1" ,
"authenticationModule" : "./auth/authentication.ts"
}
}
Microservices with Globs
{
"controllerPathGlobs" : [
"src/modules/users/controllers/**/*.ts" ,
"src/modules/orders/controllers/**/*.ts" ,
"src/modules/products/controllers/**/*.ts"
],
"noImplicitAdditionalProperties" : "throw-on-extras" ,
"spec" : {
"outputDirectory" : "api-docs" ,
"specVersion" : 3.1 ,
"yaml" : true
},
"routes" : {
"routesDir" : "src/generated" ,
"middleware" : "koa" ,
"iocModule" : "./di/container.ts" ,
"authenticationModule" : "./middleware/auth.ts"
}
}
Next Steps
tsoa.json Reference Complete schema reference with all options
CLI Commands Learn about CLI commands and flags