SDK Generator
@nestia/sdk reads your NestJS controllers and emits a client SDK — one typed function per route, plus a copy of the DTO types and an IConnection config object. The result is a normal TypeScript module a frontend, mobile app, or test suite can import.
The SDK is hand-shaped TypeScript, not a fetch wrapper around generated JSON. Renaming a DTO field on the server and re-running npx nestia sdk is a compile error on the client — exactly what you want.
Generate
import { INestiaConfig } from "@nestia/sdk";
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./src/AppModule";
const config: INestiaConfig = {
input: () => NestFactory.create(AppModule),
output: "src/api",
};
export default config;npx nestia init # one-time scaffold, if you don't have nestia.config.ts
npx nestia sdk # generate the SDKOutput: src/api/ with:
src/api/
├── HttpError.ts
├── IConnection.ts
├── Primitive.ts
├── module.ts
└── functional/
└── articles/
└── index.ts # one file per controller, one function per routeAnatomy of a generated function
/**
* Create a new article.
*
* @param input The article payload.
* @returns The stored article with `id` and `created_at` populated.
*
* @controller ArticlesController.create()
* @path POST /articles
*/
export async function create(
connection: IConnection,
input: create.Input,
): Promise<create.Output> { /* ... */ }
export namespace create {
export type Input = Primitive<IArticle.ICreate>;
export type Output = Primitive<IArticle>;
// ...
}- Function signature — derived from the controller method, including JSDoc.
Primitive<T>— the wire-form ofT(methods stripped,Datebecomesstring, etc.).IConnection— config object the client passes:host, optionalheaders, optionalsimulate.
Nothing in this file is hand-written.
Binary responses
When a route declares a binary response Content-Type with Nest’s
@Header("Content-Type", "...") or Swagger’s @ApiProduces("..."), generated
SDK functions return ReadableStream<Uint8Array<ArrayBufferLike>> instead of
trying to parse the body as JSON or text.
import { Controller, Get, Header, StreamableFile } from "@nestjs/common";
@Controller("files")
export class FileController {
@Header("Content-Type", "image/png")
@Get("thumbnail")
public thumbnail(): StreamableFile {
return new StreamableFile(/* readable source */);
}
}The generated Swagger response is emitted as type: "string" with
format: "binary". Binary detection currently covers image/*, video/*,
audio/*, application/octet-stream, and application/pdf.
INestiaConfig keys
| Key | Type | Purpose |
|---|---|---|
input | () => Promise<INestApplication> or { include: string[] } | How to find your controllers. |
output | string | Where to write the SDK. Typical: "src/api". |
distribute | string | Stage a publishable npm package layout. See Distribution. |
simulate | boolean | Embed a mock backend. See Mockup Simulator. |
e2e | string | Output directory for generated tests. See E2E. |
swagger | ISwaggerConfig | Emit a swagger.json too. See Swagger. |
propagate | boolean | SDK returns a discriminated union instead of throwing. See Propagation Mode below. |
clone | boolean | Copy DTO types into the SDK’s own structures/ directory. |
primitive | boolean | Wrap DTOs with Primitive<T> (default true). |
assert | boolean | Validate SDK call parameters at runtime via typia.assert. |
json | boolean | Use typia.assertStringify for 10× faster JSON serialization in the SDK. |
keyword | boolean | Pass SDK function arguments as a single keyword object instead of positional (default false). |
How input finds controllers
Two shapes:
// 1. NestFactory.create (recommended)
input: () => NestFactory.create(AppModule),
// 2. Glob (no Nest bootstrapping)
input: { include: ["src/**/*.controller.ts"] },Use the factory form when your app needs app.setGlobalPrefix() or app.enableVersioning() — those calls run inside the factory and the generator picks up their effects. Use the glob form for projects where bootstrapping is expensive or impossible (no DB connection available at build time).
Apply prefixes inside the factory:
input: async () => {
const app = await NestFactory.create(AppModule);
app.setGlobalPrefix("api");
app.enableVersioning({ type: VersioningType.URI, prefix: "v" });
return app;
},The generated SDK paths reflect the prefix and version automatically.
Propagation mode
Default behavior: an SDK call throws HttpError on any non-2xx response.
propagate: true swaps that for a discriminated union:
type Output = IPropagation<
{
200: IArticle;
400: TypeGuardError.IProps;
},
200 // success branch
>;
const out = await api.functional.articles.create(connection, input);
if (out.success) out.data.id; // IArticle (200)
else if (out.status === 400) out.data.expected; // TypeGuardError.IProps (400)
else out.data; // unknown — outside declared statusesThe map of status codes comes from @TypedRoute.* (success) plus every @TypedException() on the route. Range matchers ("4XX", "5XX") work the same way.
Clone mode
clone: true makes the SDK self-contained — every DTO type used in any route gets copied into the SDK’s own structures/ directory, breaking the dependency on the server’s source.
Why you’d want this:
- Your DTOs come from an ORM (Prisma
Article, TypeORM entity). Withoutclone, consumers must install@prisma/clientto compile the SDK. - You publish the SDK to npm and don’t want consumers pulling your full server tree as a transitive dependency.
Trade-off: regenerating the SDK refreshes the cloned types, but if you hand-edit the SDK after generation those edits are lost on the next npx nestia sdk run. Don’t.
Distribute
To publish the SDK as an npm package:
const config: INestiaConfig = {
input: () => NestFactory.create(AppModule),
output: "src/api",
distribute: "packages/api",
};After npx nestia sdk, packages/api/ is a publishable npm package layout. See Distribution for the customization steps.
For workspace-internal distribution (monorepo), use pnpm workspaces instead of publishing — see PNPM Monorepo.
CLI flags
npx nestia sdk # uses nestia.config.ts + tsconfig.json in cwd
npx nestia sdk --config nestia2.config.ts # alternate config
npx nestia sdk --project tsconfig2.json # alternate tsconfigUseful when one repo has two NestJS apps (e.g. a monorepo with apps/admin and apps/public).
See also
- Mockup Simulator — the in-process mock backend.
- E2E Test Generation — the test suite that comes with the SDK.
- Distribution — publishing as an npm package.
- PNPM Monorepo — workspace-internal distribution.