Skip to content

Live reloading ​

COMPATIBILITY NOTE

This guide targets express and assumes tsoa-next's current support policy: Node.js 22 or newer. We verify support on Node.js 22, 24, and 26 in CI. Examples below include npm, pnpm, and yarn variants where the command differs. We assume your setup is similar to the one recommended for getting started

Relevant API reference: @SpecPath, SpecPathOptions, SpecRequestContext, and SpecCacheHandler.

TIP

We will use nodemon and ts-node for live reloading, but any tool that allows us to hook into the reloading process will do. Alternatives may, i.e. be a combination of tsc -w and triggering tsoa spec-and-routes using onchange.

What we will talk about:

Reloading Code ​

Installing nodemon and ts-node ​

bash
npm i -D nodemon ts-node concurrently
bash
pnpm add -D nodemon ts-node concurrently
bash
yarn add -D nodemon ts-node concurrently

Creating a nodemon config ​

Now, let's create a nodemon.json inside the root folder of our project that looks like this:

json
{
  "exec": "ts-node src/server.ts",
  "watch": ["src"],
  "ext": "ts"
}

Adding a dev script ​

Let's automatically start this setup with your package manager's dev script (npm run dev, pnpm dev, or yarn dev), and, while we're at it, add build and start commands in our package.json:

diff
{
  "name": "starter",
  "version": "0.0.1",
+ "scripts": {
+   "dev": "concurrently \"nodemon\" \"nodemon -x tsoa spec-and-routes\"",
+   "build": "tsoa spec-and-routes && tsc",
+   "start": "node build/src/server.js"
+ },
  "dependencies": {
  // ...
}

Supercharging our developer experience with @SpecPath ​

@SpecPath(...) lets a controller expose a live spec or docs endpoint without reading swagger.json or openapi.yaml from disk at request time. That makes it a good fit for development workflows where you want the generated documentation to stay in sync with the same controller metadata your routes already use.

Installing a docs UI peer ​

Pick the docs UI target you want to use:

  • Express: npm i swagger-ui-express / pnpm add swagger-ui-express / yarn add swagger-ui-express
  • Koa: npm i swagger-ui-koa / pnpm add swagger-ui-koa / yarn add swagger-ui-koa
  • Hapi: npm i hapi-swagger / pnpm add hapi-swagger / yarn add hapi-swagger
  • Redoc: npm i redoc / pnpm add redoc / yarn add redoc
  • RapiDoc: npm i rapidoc / pnpm add rapidoc / yarn add rapidoc

Exposing a controller-scoped docs endpoint ​

Attach one or more @SpecPath(...) decorators to an existing controller:

ts
import { Controller, Get, Route, SpecPath } from 'tsoa-next'

@Route('users')
@SpecPath()
@SpecPath('openapi.yaml', { target: 'yaml' })
@SpecPath('docs', { target: 'swagger' })
export class UsersController extends Controller {
  @Get()
  public list(): string[] {
    return []
  }
}

This gives you:

  • GET /users/spec for JSON
  • GET /users/openapi.yaml for YAML
  • GET /users/docs for Swagger UI

Because the docs endpoint is generated from the same runtime metadata as your routes, it stays current as you edit controllers and re-run tsoa spec-and-routes.

Inspecting the Documentation ​

Now, when we navigate to localhost:3000/users/docs, we should see a current reflection of our API.

SwaggerUI

Sending requests through Swagger UI ​

We can select endpoints, click the "Try it out" button and submit some data by filling out the form. When we hit "Execute", that request will be sent to our server and the response will be displayed below the form.

SwaggerUI Response

Other built-in targets ​

If you prefer a different UI, change the target option:

  • @SpecPath('docs', { target: 'redoc' })
  • @SpecPath('docs', { target: 'rapidoc' })

If you need a fully custom response, pass a handler in target instead. You can also add cache and gate in the same options object.

Contributors

The avatar of contributor named as Vanna DiCatania Vanna DiCatania
The avatar of contributor named as Copilot Copilot

Changelog

TypeScript-first OpenAPI generation, route generation, and runtime validation.