AsyncAPI · OpenAPI · JSON Schema → TypeScript
Ship the API.
Skip the boilerplate.
The Codegen Project reads the API document you already maintain and writes the TypeScript you were going to hand-type: payload and parameter models, typed publish/subscribe functions for NATS, Kafka, MQTT, AMQP, WebSocket and SSE, and complete HTTP clients.
npm install --save-dev @the-codegen-project/cli- 3
- input formats
- 8
- generators
- 7
- protocols
- 0
- hand-written models
Spec in, code out
Your document is already the source of truth.
Stop typing it twice.
Pick an input, pick a protocol, and see the code you would write — plus every generated file standing behind it. Nothing here is mocked up.
asyncapi: 3.0.0info: title: E-commerce Order Events version: 1.0.0
channels: order-lifecycle: address: orders.{action} parameters: action: enum: [created, updated, cancelled] description: Order lifecycle action messages: OrderCreated: payload: type: object required: [orderId, customerId, items, totalAmount] properties: orderId: type: string format: uuid customerId: type: string format: uuid items: type: array items: $ref: '#/components/schemas/OrderItem' totalAmount: $ref: '#/components/schemas/Money' createdAt: type: string format: date-time
operations: publishOrderCreated: action: send channel: $ref: '#/channels/order-lifecycle' subscribeToOrderEvents: action: receive channel: $ref: '#/channels/order-lifecycle'
components: schemas: Money: type: object required: [amount, currency] properties: amount: type: number currency: type: string enum: [USD, EUR, GBP] OrderItem: type: object required: [productId, quantity, unitPrice] properties: productId: type: string quantity: type: integer unitPrice: $ref: '#/components/schemas/Money'src/index.tsyou write thisimport {connect} from 'nats';import {publishToPublishOrderCreated} from './__gen__/nats';import {OrderItem} from './__gen__/payload/OrderItem';import {Money} from './__gen__/payload/Money';import {MoneyCurrencyEnum} from './__gen__/payload/MoneyCurrencyEnum';
// `items` and `totalAmount` are typed as the generated models, not as plain// objects - a type with private fields will not accept an object literal.const eur = (amount: number) => new Money({amount, currency: MoneyCurrencyEnum.EUR});
const nc = await connect({servers: 'localhost:4222'});
// Fully typed. Rename a field in the spec and this stops compiling.await publishToPublishOrderCreated({ message: { orderId: '3f0c9e1a-6f1e-4a5b-9c22-8c0a7f1d2e33', customerId: '9ab1c7d4-2e55-4f01-8a0f-1d4b6e9c0a12', items: [ new OrderItem({productId: 'CG-1', quantity: 2, unitPrice: eur(21)}) ], totalAmount: eur(42) }, // type Action = 'created' | 'updated' | 'cancelled' parameters: {action: 'created'}, nc});natsTry your own spec in the playground →Eight presets
Generate exactly as much as you want
Presets compose. Take just the models, or wire up the whole client — the renderer resolves the dependency order for you.
payloads
Typed payload and message models that serialize straight into your wire format.
parameters
Parameter models that interpolate values into subjects, topics and URL paths.
headers
Message header models, with optional runtime validation of what arrives.
types
Type aliases and enums derived from the constraints already in your document.
channels
Protocol-specific publish, subscribe, request and reply functions per operation.
client
One class wrapping the channel functions, with connection handling built in.
models
Plain typed models via Modelina, with none of the messaging machinery.
custom
Your own render function, fed the parsed document and other generators’ output.
AsyncAPI and OpenAPI support all eight. JSON Schema supports models and custom. See the full support matrix →
One document, every transport
Swap the broker, keep the call sites
The channels preset emits idiomatic code per protocol — JetStream for NATS, consumer groups for Kafka, user properties for MQTT v5, exchanges and queues for AMQP.
Three commands
From spec to typed code in one sitting
Install
A dev dependency, a global binary, or a signed installer per platform. Node.js 22+.
npm install --save-dev @the-codegen-project/cliInitialize
codegen initwalks you through it interactively, or takes flags for CI. It writes the config file — JSON, YAML, TS, ESM or CJS.codegen init # or non-interactivelycodegen init --no-tty \ --input-type asyncapi \ --input-file ./asyncapi.yml \ --include-payloads \ --include-channels \ --channels-protocols natsGenerate
Once, or on every change with
--watch. Commit the output or generate it in CI — both work.codegen generate # keep it in sync while you edit the speccodegen generate --watch
Working with an AI assistant? There is an MCP server and a rules file for that.
💎 Sponsors
Delete your hand-written models today
Apache-2.0, free forever, and built in the open. Bring an AsyncAPI, OpenAPI or JSON Schema document and see what falls out.
