Explanation

Architecture

Understand how Kubb converts API specifications into generated files through adapters, the AST, plugins, parsers, and storage.

Kubb separates the input specification, generated content, output syntax, and destination. Each layer has one job:

LayerResponsibility
AdapterRead the specification and produce an InputNode.
ASTDescribe schemas and operations in a shared tree.
PluginRun generators that emit FileNodes.
ParserConvert emitted nodes into source code.
StoragePersist the generated files.

You declare the input spec, the output folder, an adapter, and the plugins to run. defineConfig pre-wires the OpenAPI adapter and the default parsers.

inputoutputadapterplugins

From one operation to generated files

Consider a specification with GET /pet/{petId}, the operation ID getPetById, and a response referring to a reusable Pet schema.

  1. The adapter reads the specification and resolves its references into schemas and operations.
  2. The shared AST describes the Pet fields, the path parameter, and the operation’s response. It does not choose Axios, Fetch, or Zod.
  3. The TypeScript plugin generates model and response types. An Axios plugin generates a getPetById client that imports those types. A Zod plugin can generate validation schemas from the same input.
  4. A parser turns each plugin’s emitted nodes into source text. Storage writes the resulting files to the configured destination.

The same specification can therefore produce several outputs in one run. The first-client tutorial follows this operation using TypeScript and Axios.

Configuration

defineConfig from kubb/config supplies the OpenAPI adapter, TypeScript/TSX/Markdown parsers, filesystem storage, and a barrel plugin. Barrel generation follows output.barrel at the root or on individual plugins.

Choose the outputs with plugins. Configure the destination with output.path. The configuration reference lists the available fields and defaults.

Adapters

An adapter resolves input-specific details, including references, nullability, discriminators, and formats. The default OpenAPI adapter supports OpenAPI 2.0, 3.0, and 3.1. A custom adapter converts another input format into the same AST, so downstream plugins do not read that format directly.

Input specOpenAPI 2/3
adapter.parse(source)
InputNodeschemas + operations
You hand Kubb an OpenAPI 2 or 3 document.

AST

The AST is the shared model between the adapter and plugins. Normalizing the input once means each plugin can work with schemas and operations without implementing OpenAPI reference resolution itself. A new adapter can feed the same plugins, and a new plugin can consume the same model.

An InputNode contains reusable schemas and operations. Operations connect parameters, request bodies, and responses to schema nodes. Request bodies and responses have one ContentNode per content type.

InputNode
├─ schemas: SchemaNode[]
└─ operations: OperationNode[]
├─ parameters: ParameterNode[]
├─ requestBody: RequestBodyNode
└─ responses: ResponseNode[]

Nodes carry a kind discriminant. Schemas also carry a type discriminant. The transform visitor rewrites nodes, while collect gathers matching nodes. Import the ast namespace from kubb/kit. See AST reference for node builders, visitors, and guards.

Plugins and generators

Each plugin owns an output: types, clients, hooks, validators, mocks, or custom files. Its generators handle individual schemas, individual operations, or the complete operation set.

Macros transform AST nodes before generators use them. They run per plugin, so one plugin's transformations do not modify another plugin's input. Resolvers keep names and paths consistent across generated files.

For the pet operation above, the type and client plugins need to agree on the response type’s name and file path. The client reads the type plugin’s resolver so its imports continue to work when names are customized.

See Extension model for how these pieces cooperate.

Parsers

Each parser claims file extensions. Kubb selects it for the emitted file, prints nodes during generation, and assembles the final source through parse. The default parsers handle .ts, .tsx, and .md.

These responsibilities differ: the plugin chooses which files and declarations to emit; a printer chooses how an individual schema appears in that output; the parser assembles the file’s source text.

A printer inside a generator handles schema-specific output. A parser handles the assembled file. See Customize printers and Parser reference.

Storage

Storage separates generation from its destination. Keeping this boundary lets the same build run on disk for a CLI workflow, or in memory for tests and applications that consume generated content directly. fsStorage() writes to disk. memoryStorage() keeps results in a Map. Kubb skips writes when the stored content already matches.

A custom driver implements the Storage interface to target another backend. Formatting, linting, and CLI post-generation commands follow generation.

See also