Skip to Content
📖 Guide DocumentsS/W Development KitSDK Builder

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

nestia.config.ts
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;
Terminal
npx nestia init # one-time scaffold, if you don't have nestia.config.ts npx nestia sdk # generate the SDK

Output: src/api/ with:

src/api/ ├── HttpError.ts ├── IConnection.ts ├── Primitive.ts ├── module.ts └── functional/ └── articles/ └── index.ts # one file per controller, one function per route

Anatomy of a generated function

src/api/functional/articles/index.ts (excerpt)
/** * 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 of T (methods stripped, Date becomes string, etc.).
  • IConnection — config object the client passes: host, optional headers, optional simulate.

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

KeyTypePurpose
input() => Promise<INestApplication> or { include: string[] }How to find your controllers.
outputstringWhere to write the SDK. Typical: "src/api".
distributestringStage a publishable npm package layout. See Distribution.
simulatebooleanEmbed a mock backend. See Mockup Simulator.
e2estringOutput directory for generated tests. See E2E.
swaggerISwaggerConfigEmit a swagger.json too. See Swagger.
propagatebooleanSDK returns a discriminated union instead of throwing. See Propagation Mode below.
clonebooleanCopy DTO types into the SDK’s own structures/ directory.
primitivebooleanWrap DTOs with Primitive<T> (default true).
assertbooleanValidate SDK call parameters at runtime via typia.assert.
jsonbooleanUse typia.assertStringify for 10× faster JSON serialization in the SDK.
keywordbooleanPass 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 statuses

The 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). Without clone, consumers must install @prisma/client to 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:

nestia.config.ts
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

Terminal
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 tsconfig

Useful when one repo has two NestJS apps (e.g. a monorepo with apps/admin and apps/public).


See also

Last updated on