Generate Your SDK
So far youβve built a typed server. This is the part most teams come for: every controller you wrote becomes a typed function in a generated SDK that a frontend can import and call. No fetch, no URL strings, no hand-maintained DTOs in two places.
1. The config file
Nestia reads nestia.config.ts at the project root. If you used the starter it is already there; otherwise:
npx nestia initOpen it:
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;Three things matter:
inputβ how Nestia finds your controllers. A function returning yourNestApplicationis the most reliable form; it picks up every module, prefix, and versioning rule you set on the app.outputβ where the generated SDK lives. We recommendsrc/api.- Thatβs all you need for the SDK. We will add
swaggerande2ekeys in later chapters.
2. Generate
npx nestia sdkYou should see a tree appear under src/api/:
src/api/
βββ HttpError.ts
βββ IConnection.ts
βββ Primitive.ts
βββ module.ts
βββ functional/
βββ articles/
βββ index.ts # one file per controllerOpen src/api/functional/articles/index.ts and you will find one exported function per controller method. The function signature is derived from your TypeScript types:
/**
* 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>;
// ...
}The JSDoc came from your controllerβs JSDoc. The Input / Output types came from your TypeScript types. Nothing about this file is hand-written.
3. The shape of an SDK call
Every generated function takes an IConnection as the first argument and the rest of the parameters in source order. IConnection is a small config object exported from the SDK that tells it where your server lives and what headers to send β no class, no client to instantiate, just a plain object.
import api from "@my-app/api";
// or, when the SDK lives in the same repo:
import * as api from "../api";
const connection: api.IConnection = {
host: "http://localhost:37001",
};
const article = await api.functional.articles.create(connection, {
title: "Hello",
body: "World",
});connection.hostpoints at your server.connection.headers(optional) is merged into every request β handy forAuthorization.- The function returns the typed response. Your IDE autocompletes
article.id,article.created_at, etc.
A 4xx / 5xx response throws an HttpError. Mistyped arguments are a TypeScript compile error, not a 400 at runtime.
4. Where to put the generated SDK
Three common shapes:
Single repo
Single repo: put output: "src/api" inside the NestJS project. Tests inside the repo import the SDK from ../api. Good for solo projects and prototypes.
5. When to regenerate
Re-run npx nestia sdk whenever your controllers, DTOs, or nestia.config.ts change. In a typical workflow you wire it into your build:
{
"scripts": {
"build": "ttsc && npx nestia sdk"
}
}If you also want Swagger and e2e, use the combined command (npx nestia all) covered in the next chapters.
6. What you can do now
The generated SDK is a normal TypeScript module. You can:
- Import it from a Next.js / Vite / React Native client.
- Use it inside Node scripts and Lambda functions.
- Bundle it into a published
npmpackage for external partners. - Drive it from tests (Chapter 8 will do exactly that).
Next
You have an SDK. Letβs Call Your API from a tiny client and feel what type-safe RPC looks like.