Install
Nestia runs on TypeScript 7 through ttsc.
Install the compiler toolchain, the runtime packages, and the CLI explicitly:
npm
npm i -D ttsc typescript
npm i typia @nestia/core @nestia/sdk @nestia/fetcher
npm i -D nestia@nestia/sdk is a runtime dependency. The generated SDK and runtime Swagger
composition both resolve it while the Nestia transform attaches route metadata.
ttsc must be 0.19.2 or newer. ttsc compiles the Nestia transform from Go source on first use, and that source reports the compiled project’s reference graph through an API older releases do not have, so an older ttsc fails the plugin build instead of silently producing a transform without it. @nestia/core declares the floor as an optional peer dependency.
tsconfig.json
Keep the NestJS decorator metadata flags. Do not add compilerOptions.plugins
for normal Nestia setup; ttsc discovers @nestia/core, @nestia/sdk, and
typia from their package manifests.
{
"compilerOptions": {
"strict": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}Transform options
No plugin config means Nestia uses its defaults:
@TypedBodyvalidates with"validate".@TypedRouteserializes with"assert".- LLM schema restrictions are off.
Add compilerOptions.plugins only when you want to override those options:
{
"compilerOptions": {
"plugins": [
{ "transform": "typia/lib/transform", "enabled": false },
{
"transform": "@nestia/core/native/transform.cjs",
"validate": "validatePrune",
"stringify": "validate.log",
"llm": { "strict": true }
}
]
}
}If a nest new project has tsconfig.build.json, point ttsc at that file so
test files stay out of production output:
{
"scripts": {
"build": "ttsc -p tsconfig.build.json"
}
}Build
Replace NestJS CLI build commands with ttsc / ttsx.
{
"scripts": {
"build": "ttsc",
"start": "node dist/main.js",
"start:dev": "ttsc && concurrently \"ttsc --watch\" \"node --watch dist/main.js\"",
"start:script": "ttsx src/main.ts"
}
}nest build, nest start, tsc, ts-node, and tsx do not run the Nestia
transform. Use ttsc for builds and ttsx for direct TypeScript execution.
start:dev builds once before starting the watchers on purpose. concurrently starts both commands immediately, and node --watch exits with Cannot find module if its entry does not exist yet — it only begins watching after a successful first load — so without the leading build it loses the race against the initial ttsc --watch compile and never comes back.
Plugin cache
ttsc compiles the Nestia transform from Go source, which is why the first build reports building source plugin "@nestia/core". It is compiled once per cache key and reused afterwards; the message appears again only when something in that key changes.
Two caches decide whether that work repeats. The compiled plugin lives in TTSC_CACHE_DIR, defaulting to <workspace>/node_modules/.cache/ttsc, and the Go build cache lives in TTSC_GO_CACHE_DIR or GOCACHE. Neither falls back to a location outside the workspace, so rm -rf node_modules reclaims both — and discards both.
The cache key covers the ttsc and TypeScript-Go versions, the platform, the Go toolchain, and the plugin’s own source. It does not cover your application code. A container image that installs dependencies in one layer and copies sources in a later one can therefore warm the plugin during the dependency layer and keep it across every source change, or mount both caches:
RUN --mount=type=cache,target=/ttsc-cache \
--mount=type=cache,target=/go-cache \
TTSC_CACHE_DIR=/ttsc-cache TTSC_GO_CACHE_DIR=/go-cache pnpm buildttsc needs a Go toolchain on PATH; point TTSC_GO_BINARY at an absolute path when the image keeps it somewhere unusual.
Generate
Create nestia.config.ts once, then run the generators:
npx nestia init
npx nestia sdk
npx nestia swagger
npx nestia e2e
npx nestia allinit writes a starter config. sdk, swagger, and e2e emit one artifact
each; all runs the three together.
Bundlers
A normal NestJS server should compile with ttsc directly. When a bundler owns
the build, install @ttsc/unplugin and add the adapter for that bundler.
npm
npm i -D @ttsc/unpluginimport ttsc from "@ttsc/unplugin/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [ttsc()],
});Use the matching import path for other bundlers:
@ttsc/unplugin/webpack, @ttsc/unplugin/rspack,
@ttsc/unplugin/esbuild, @ttsc/unplugin/next,
@ttsc/unplugin/rollup, @ttsc/unplugin/rolldown,
@ttsc/unplugin/farm, or @ttsc/unplugin/bun.
A persistent bundler cache stays correct across builds without any extra configuration. A bundler erases type-only imports from its own module graph, so nothing in that graph connects a controller’s generated validator to the DTO declaration it was generated from; the Nestia transform reports the compiler’s own reference graph to the adapter, which registers the DTO as an input of the controller module. Editing the DTO’s type rebuilds the controller instead of replaying the cached module, in watch mode and in a kept filesystem cache alike.
Troubleshooting
no transform has been configured: the project was built bytsc,nest build, SWC, Babel, or another path that skippedttsc.- Empty SDK or Swagger output: confirm the controllers use
@TypedRouteand that the generator reads the sametsconfig.jsonas the build. - NestJS DI fails: restore
experimentalDecoratorsandemitDecoratorMetadata; NestJS still needs them for constructor injection. - Bundler output skips validation: add the matching
@ttsc/unpluginadapter to the bundler config. - Plugin build fails on an unknown Go symbol:
ttscis older than 0.19.2. Upgrade it; the version floor is listed under Install.