# Kubb > Documentation for the Kubb code generation ecosystem. Canonical Origin: https://kubb.dev/ ## LLM Resources - [Full Content](https://kubb.dev/llms-full.txt): Complete page content in markdown format. --- - **Page:** About · Kubb - **Source:** https://kubb.dev/about - **Description:** Learn about Kubb's origin, philosophy, and plugin-based architecture. Discover why it's the meta framework for code generation and why it's named after the Swedish lawn game Kubb. # About Kubb ## The Meta Framework for Code Generation Kubb is the meta framework for code generation. Like Next.js on top of React, Kubb is a meta framework on top of code generation. Your OpenAPI specification is the source of truth; Kubb provides the pipeline, [plugins](/docs/5.x/explanation/extensions#plugins), and extensibility you need. Every output format is an independent plugin. The core is intentionally minimal. Plugins compose. You bring your spec, configure the outputs you need, and Kubb generates everything in one `kubb generate` run: TypeScript types, API clients, React Query hooks, Zod schemas, MSW handlers, and Faker mocks. ## What does "Kubb" mean? Kubb is named after the popular Swedish lawn game [Kubb](https://en.wikipedia.org/wiki/Kubb). The name reflects the project's philosophy: just as the game Kubb uses wooden blocks (kubbar), our Kubb uses modular plugins as building blocks. > Kubb (pronounced [kubː] in Swedish and Gutnish) is a lawn game where the objective is to knock over wooden blocks (kubbar) by throwing wooden batons (kastpinnar) at them. Kubb can be described as a combination of bowling and horseshoes. The name is short, sounds like "cube" (fitting for a modular system), and happens to be Stijn's favorite summer game. ## Project philosophy Every feature in Kubb is implemented as a separate [plugin](/docs/5.x/explanation/extensions#plugins). This is what makes Kubb a _meta_ framework rather than a fixed code generator: there is no monolithic output, only composable pieces you assemble. ### Current focus Kubb currently specializes in generating TypeScript code from OpenAPI/Swagger specifications. To add support for a new specification format, you write a new [adapter](/docs/5.x/explanation/architecture#adapters). The entire plugin ecosystem works unchanged on top of it. ## Creator and maintainer Kubb is created and maintained by [Stijn Van Hulle](https://stijnvanhulle.be). Follow [@stijnvanhulle on BlueSky](https://bsky.app/profile/stijnvanhulle.bsky.social) for release announcements, new plugins, and development notes. ## Community and contributions Use [GitHub Discussions](https://github.com/kubb-labs/kubb/discussions) for questions, [Discord](https://discord.gg/shfBFeczrm) for real-time chat, and [GitHub Issues](https://github.com/kubb-labs/kubb/issues) for bugs and feature requests. Kubb is MIT-licensed and open to contributions. Bug fixes, new plugins, and documentation improvements are all welcome. See the [plugin guide](/docs/5.x/tutorials/creating-plugins) to build your own. ## Support the project If Kubb saves you time, consider [sponsoring on GitHub](https://github.com/sponsors/stijnvanhulle). --- - **Page:** Kubb registry · Kubb - **Source:** https://kubb.dev/registry - **Description:** The list of Kubb extensions that the Kubb CLI, Kubb Studio and kubb.dev read. It is a set of static JSON documents under one base URL. ```yaml meta: og:image: https://kubb.dev/_og/s/o_5df8ae67953ba91c.png og:image:height: "630" og:image:type: image/png og:image:width: "1200" twitter:image: https://kubb.dev/_og/s/o_5df8ae67953ba91c.png ``` **Extensions** # **Kubb registry** [Browse extensions](https://kubb.dev/extensions) [Submit an extension](https://kubb.dev/docs/5.x/how-to/submit-to-the-registry) The list of Kubb extensions that the Kubb CLI, Kubb Studio and kubb.dev read. It is a set of static JSON documents under one base URL. - [**Plugins****14**](https://kubb.dev/extensions/kind/plugins) - [**Adapters****1**](https://kubb.dev/extensions/kind/adapters) - [**Parsers****2**](https://kubb.dev/extensions/kind/parsers) - **Last build**Oct 15, 2026 **$**curl https://kubb.dev/registry/index.jsoncurl https://kubb.dev/registry/index.json ## **Recently added** - [**Axios**@kubb/plugin-axiosOct 12, 2026](https://kubb.dev/extensions/kubb-labs/plugin-axios) - [**Barrel**@kubb/plugin-barrelOct 12, 2026](https://kubb.dev/extensions/kubb-labs/plugin-barrel) - [**Client**@kubb/plugin-clientOct 12, 2026](https://kubb.dev/extensions/kubb-labs/plugin-client) - [**Cypress**@kubb/plugin-cypressOct 12, 2026](https://kubb.dev/extensions/kubb-labs/plugin-cypress) - [**Faker**@kubb/plugin-fakerOct 12, 2026](https://kubb.dev/extensions/kubb-labs/plugin-faker) ```json {"@context":"https://schema.org","@graph":[{"@id":"https://kubb.dev/#website","@type":"WebSite","description":"Documentation for the Kubb code generation ecosystem.","name":"Kubb","url":"https://kubb.dev/","publisher":{"@id":"https://kubb.dev/#identity"}},{"@id":"https://kubb.dev/registry#webpage","@type":"WebPage","description":"The list of Kubb extensions that the Kubb CLI, Kubb Studio and kubb.dev read. It is a set of static JSON documents under one base URL.","name":"Kubb registry · Kubb","url":"https://kubb.dev/registry","isPartOf":{"@id":"https://kubb.dev/#website"},"potentialAction":[{"@type":"ReadAction","target":["https://kubb.dev/registry"]}],"primaryImageOfPage":{"@id":"https://kubb.dev/#logo"}},{"@id":"https://kubb.dev/#identity","@type":"Organization","description":"Kubb turns an API spec, such as OpenAPI, into TypeScript types, API clients, hooks, Zod schemas and mocks. Define your API once and keep every layer in sync.","email":"kubb@kubb.dev","name":"Kubb","url":"https://kubb.dev","founder":{"@id":"https://kubb.dev/#founder"},"logo":{"@id":"https://kubb.dev/#logo"},"sameAs":["https://github.com/kubb-labs/kubb","https://discord.gg/shfBFeczrm","https://www.linkedin.com/company/kubb-labs"]},{"@id":"https://kubb.dev/#logo","@type":"ImageObject","caption":"Kubb","contentUrl":"https://kubb.dev/logo.png","inLanguage":"en","url":"https://kubb.dev/logo.png"}]} ``` --- - **Page:** All extensions · Kubb - **Source:** https://kubb.dev/extensions - **Description:** Plugins generate code, adapters read your API spec, and parsers print the files. Every listed version is reviewed. ```yaml meta: og:image: https://kubb.dev/_og/s/o_49c2eed7eadc568d.png og:image:height: "630" og:image:type: image/png og:image:width: "1200" twitter:image: https://kubb.dev/_og/s/o_49c2eed7eadc568d.png ``` **Extensions** # **All extensions** Plugins generate code, adapters read your API spec, and parsers print the files. Every listed version is reviewed. 17 extensions · updated Oct 15, 2026 [`plugins: [pluginTs()]`
${{ steps.snapshot.outputs.tarball-url }}. See the [action reference](/docs/5.x/reference/github-actions) for all inputs, outputs, and runtime behavior.
## Review and install the result
Open the snapshot in Studio to review generated changes. To consume the generated package, follow [Install the snapshot](/docs/5.x/integrations/ci#install-the-snapshot).
> [!NOTE]
> Snapshots expire after seven days. Schedule a default-branch run if it can go a week without a push.
::
---
- **Page:** Contributing · Kubb
- **Source:** https://kubb.dev/docs/5.x/community/contributing
- **Description:** A concise guide to contributing to Kubb core and Kubb plugins.
# Contributing
There are two places to contribute:
1. [Kubb core](#kubb-core): the runtime, [AST](/docs/5.x/explanation/architecture#ast), [adapter](/docs/5.x/explanation/architecture#adapters), [parsers](/docs/5.x/explanation/architecture#parsers), the [authoring kit](/docs/5.x/reference/kit), and built-in plugins in [`kubb-labs/kubb`](https://github.com/kubb-labs/kubb).
2. [Kubb plugins](#kubb-plugins): community and official plugins in the registry at [`kubb-labs/plugins`](https://github.com/kubb-labs/plugins).
First, check the open [issues](https://github.com/kubb-labs/kubb/issues) and [pull requests](https://github.com/kubb-labs/kubb/pulls) so you don't duplicate work. Say hello on [Discord](https://discord.gg/4dQjA6vrWX).
## Prerequisites
- [Node.js](https://nodejs.org/en/download) 22 or later.
- [pnpm](https://pnpm.io/installation) 11 or later.
- [Git](https://git-scm.com/) and, optionally, the [GitHub CLI](https://cli.github.com/).
## Kubb core
The monorepo at [`kubb-labs/kubb`](https://github.com/kubb-labs/kubb) holds everything in the `kubb` and `@kubb/*` packages.
::steps{level="3"}
### Fork and clone {#_1-fork-and-clone}
```shell [Terminal]
gh repo fork kubb-labs/kubb --clone
cd kubb
```
### Install dependencies {#_2-install-dependencies}
```shell [Terminal]
pnpm install
```
### Create a branch {#_3-create-a-branch}
```shell [Terminal]
git checkout -b feat/your-feature-name
```
### Iterate {#_4-iterate}
Run a single package in watch mode:
```shell [Terminal]
pnpm -F @kubb/core start
```
Run the test suite:
```shell [Terminal]
pnpm run test
```
::
### What lives where
| Path | What lives there |
| ----------------------------- | ----------------------------------------------------------------------- |
| `packages/core/` | Plugin runtime, build loop, `defineExtension`/`createKubb` API. |
| `packages/kit/` | Authoring toolkit re-exported through `kubb/kit`, holding `defineExtension`, `defineGenerator`, `createRenderer`, and the `ast` node builders. |
| `packages/ast/` | Universal AST and visitor utilities. |
| `packages/adapter-oas/` | OpenAPI adapter that parses an OAS 2.0/3.x spec into the AST. |
| `packages/parser-ts/` | Parser that turns the AST into TypeScript and TSX source. |
| `packages/parser-md/` | Parser that turns the AST into Markdown source. |
| `packages/plugin-barrel/` | Barrel file plugin (`enforce: 'post'`). |
| `packages/renderer-jsx/` | JSX renderer used by plugins that emit components. |
| `packages/cli/` | The `kubb` CLI entry point. |
| `packages/mcp/` | MCP server runtime. |
| `packages/unplugin-kubb/` | Bundler integrations (Vite, webpack, Rollup, Rolldown, Rspack, esbuild, Farm, Nuxt, Astro). |
| `packages/kubb/` | The meta package that re-exports `defineConfig` with sensible defaults. |
### Quality gates
Run these locally before pushing. CI runs the same commands.
```shell [Terminal]
pnpm run typecheck
pnpm run lint
pnpm run test
```
## Kubb plugins
Build a community plugin in your own repository, or propose an official one in the core monorepo.
### Build a community plugin
1. Follow the [Creating Your First Plugin](/docs/5.x/tutorials/creating-plugins) guide.
2. Use [`@kubb/plugin-axios`](https://github.com/kubb-labs/plugins/tree/main/packages/plugin-axios) as the layout to copy.
3. Publish to npm under the `kubb-plugin-*` naming convention.
4. Add a `kubb-extension.json` and a `docs/` folder with an `overview.md`, then submit the package to the Kubb registry. See [Publish a plugin](/docs/5.x/how-to/publish-a-plugin).
### Propose an official plugin
Official plugins ship under `@kubb/plugin-*`. First, [open an issue](https://github.com/kubb-labs/plugins/issues/new/choose) on the [`kubb-labs/plugins`](https://github.com/kubb-labs/plugins) repo to discuss scope and naming. Once approved, scaffold the package under `packages/plugin-`: `listPets200Schema` becomes `listPetsStatus200Schema`.
- Output uses chained Zod 4 calls. Functional wrappers remain for `mini: true`. Getters are used only for circular references.
See [Zod options](/extensions/kubb-labs/plugin-zod/options).
## React Query {#plugin-react-query}
Register an Axios or Fetch client plugin. `client` is now `'axios' | 'fetch'`, auto-detected when exactly one client is registered. Move `baseURL` and validation to that client. Remove the query plugin's `parser`.
Set `hooks: true` to keep `use*` hooks. The default `false` still emits keys and option factories.
Queries and mutations use grouped `*Options`. The trailing client config excludes `path`, `query`, `body`, `headers`, and `url`. `TData` now contains only 2xx responses. Errors use `TError`. Remove imports of `*MutationKey` type aliases and use the runtime key helper.
The generated auto `enabled` guard is removed. Set TanStack Query's `enabled` or `skipToken` when deferring a request. Suspense hooks always run. See [React Query options](/extensions/kubb-labs/plugin-react-query/options).
## Vue Query {#plugin-vue-query}
Apply the React Query changes above. Each parameter group accepts `MaybeRefOrGetter`, and generated client calls unwrap it with `toValue()`. Set `hooks: true` to retain composables. See [Vue Query options](/extensions/kubb-labs/plugin-vue-query/options).
## SWR {#plugin-swr}
Use the same client selector, grouped parameters, and client-level validation. Remove `mutation.paramsToTrigger`. Mutation parameters always pass through `trigger()`:
```typescript [src/app.ts]
useUpdatePet().trigger({ path: { petId }, body: pet })
```
SWR drops the parameter-presence guard and keys requests off `shouldFetch`. Set it to `false` to disable a request. See [SWR options](/extensions/kubb-labs/plugin-swr/options).
## Faker {#plugin-faker}
Remove `paramsCasing` and `mapper`. Use macros or printers, keeping mock values compatible with the TypeScript output. `createPet` keeps its name but accepts generic `TData`, preserving the types of override fields in its return value. See [Faker options](/extensions/kubb-labs/plugin-faker/options).
## MSW {#plugin-msw}
The `parser`, `handlers`, and `baseURL` options retain their v4 behavior. Generated handlers use `HttpResponseResolver` typed against request bodies and headers. Apply the shared resolver, adapter `contentType`, and generator-option migrations. See [MSW options](/extensions/kubb-labs/plugin-msw/options).
## Cypress {#plugin-cypress}
Request helpers take grouped `*Options` followed by the unchanged `Partial`. Remove `dataReturnType`. Helpers yield the body as `Cypress.Chainable`. HTTP methods are uppercase and imports use `*Options`/`*Response` names. `baseURL`, `exclude`, `include`, and `override` retain their shape. There is no validator option. See [Cypress options](/extensions/kubb-labs/plugin-cypress/options).
## MCP {#plugin-mcp}
Register TypeScript, Zod, and an Axios or Fetch client. `client` selects the registered client. Move `baseURL` there and remove `paramsCasing`. Handlers receive grouped `*Options` plus the MCP `ServerContext`, delegate to generated client operations, and read `res.data`. See [MCP options](/extensions/kubb-labs/plugin-mcp/options).
## Verify the upgrade {#verify-the-upgrade}
Run `kubb generate`, review generated-file changes, and type-check your application. Update response imports for `Status` names, Zod inferred-type imports for `Type`, and imports from renamed tag folders. Enable formatting, linting, and barrels explicitly if needed.
---
- **Page:** Generate with Rolldown · Kubb
- **Source:** https://kubb.dev/docs/5.x/integrations/rolldown
- **Description:** Run Kubb code generation during Rolldown builds.
# Generate with Rolldown
::steps{level="2"}
## Install Kubb and your output plugins
Follow the [installation guide](/docs/5.x/how-to/installation) to add Kubb and the plugins your output needs. The integration ships with `kubb` as `unplugin-kubb`.
## Configure the integration
Import your shared `kubb.config.ts` and pass it to the integration. The `config` must be a single object, not the array or function forms `defineConfig` accepts. Run the build command of your tool to generate the files.
```typescript [rolldown.config.ts]
import kubb from 'kubb/rolldown'
import { defineConfig } from 'rolldown'
import config from './kubb.config'
export default defineConfig({
input: 'src/index.ts',
plugins: [kubb({ config })],
})
```
> [!NOTE]
> Bundler integrations apply fewer defaults than the CLI: no Markdown parser, no reporters, and no `output.postGenerate` commands. Use the CLI when you need them. See [Defaults](/docs/5.x/reference/configuration#defaults).
::
---
- **Page:** Integrations overview · Kubb
- **Source:** https://kubb.dev/docs/5.x/integrations/overview
- **Description:** Connect Kubb to Studio, publish snapshots from CI, or run generation during a Vite, webpack, Rollup, Rolldown, Rspack, esbuild, Farm, Nuxt, or Astro build.
# Integrations overview
Run Kubb from Studio, from CI, or during your build. Each integration uses your shared `kubb.config.ts`.
## Studio
::card-group
:::card{title="Kubb Studio" icon="i-iconoir-cube" to="/docs/5.x/integrations/studio"}
Connect a local project to Studio and review generated files in the browser.
:::
::
## CI
::card-group
:::card{title="CI snapshots" icon="i-iconoir-git-merge" to="/docs/5.x/integrations/ci"}
Publish installable Studio snapshots from any CI provider.
:::
:::card{title="GitHub Actions" icon="i-simple-icons-githubactions" to="/docs/5.x/integrations/github-actions"}
Publish snapshots from GitHub Actions and review generated-file changes.
:::
:::card{title="GitLab CI" icon="i-simple-icons-gitlab" to="/docs/5.x/integrations/gitlab"}
Publish snapshots from GitLab CI and review generated-file changes.
:::
::
## Build tools
Kubb runs generation during your build through `unplugin-kubb`, included with `kubb`. Each integration takes your `kubb.config.ts` as a single `config` object and generates when the tool builds.
::card-group
:::card{title="Vite" icon="i-simple-icons-vite" to="/docs/5.x/integrations/vite"}
Import from `kubb/vite`.
:::
:::card{title="webpack" icon="i-simple-icons-webpack" to="/docs/5.x/integrations/webpack"}
Import from `kubb/webpack`.
:::
:::card{title="Rollup" icon="i-simple-icons-rollupdotjs" to="/docs/5.x/integrations/rollup"}
Import from `kubb/rollup`.
:::
:::card{title="Rolldown" icon="i-simple-icons-rolldown" to="/docs/5.x/integrations/rolldown"}
Import from `kubb/rolldown`.
:::
:::card{title="Rspack" icon="i-iconoir-journal" to="/docs/5.x/integrations/rspack"}
Import from `kubb/rspack`.
:::
:::card{title="esbuild" icon="i-simple-icons-esbuild" to="/docs/5.x/integrations/esbuild"}
Import from `kubb/esbuild`.
:::
:::card{title="Farm" icon="i-iconoir-light-bulb" to="/docs/5.x/integrations/farm"}
Import from `kubb/farm`.
:::
:::card{title="Nuxt" icon="i-simple-icons-nuxt" to="/docs/5.x/integrations/nuxt"}
Import from `kubb/nuxt`.
:::
:::card{title="Astro" icon="i-simple-icons-astro" to="/docs/5.x/integrations/astro"}
Import from `kubb/astro`.
:::
::
Vite, Nuxt, and Astro generate during builds only. Run `kubb generate` before starting their development servers.
> [!NOTE]
> Bundler integrations apply fewer defaults than the CLI: no Markdown parser, no reporters, and no `output.postGenerate` commands. See [Defaults](/docs/5.x/reference/configuration#defaults).
---
- **Page:** Generate with Rollup · Kubb
- **Source:** https://kubb.dev/docs/5.x/integrations/rollup
- **Description:** Run Kubb code generation during Rollup builds.
# Generate with Rollup
::steps{level="2"}
## Install Kubb and your output plugins
Follow the [installation guide](/docs/5.x/how-to/installation) to add Kubb and the plugins your output needs. The integration ships with `kubb` as `unplugin-kubb`.
## Configure the integration
Import your shared `kubb.config.ts` and pass it to the integration. The `config` must be a single object, not the array or function forms `defineConfig` accepts. Run the build command of your tool to generate the files.
```typescript [rollup.config.ts]
import kubb from 'kubb/rollup'
import config from './kubb.config'
export default {
input: 'src/index.ts',
plugins: [kubb({ config })],
}
```
> [!NOTE]
> Bundler integrations apply fewer defaults than the CLI: no Markdown parser, no reporters, and no `output.postGenerate` commands. Use the CLI when you need them. See [Defaults](/docs/5.x/reference/configuration#defaults).
::
---
- **Page:** Connect a project to Studio · Kubb
- **Source:** https://kubb.dev/docs/5.x/integrations/studio
- **Description:** Connect a local Kubb project to Studio, review generated files, and keep an agent running in the background.
# Connect a project to Studio
Use [Kubb Studio](https://kubb.studio) to generate and review a project's clients, types, schemas, hooks, and mocks from the browser. Start with Kubb installed and a `kubb.config.ts` in your project. `kubb studio` needs Kubb 5.6.1 or later, because Studio refuses older agents. `kubb studio snapshot` needs Kubb 5.6.2 or later.
For a quick trial without local setup, use Studio's shared sandbox with a spec you are comfortable providing outside your environment. For a persistent team connection on your infrastructure, use the [Docker agent](https://hub.docker.com/r/kubblabs/kubb-agent). An organization admin approves its pairing code.
## Connect your project
Run this command from the project directory:
```shell [Terminal]
kubb studio
```
Approve the pairing code in the Studio window and answer the permission prompts. Each project directory pairs as its own agent. Keep the command running, select the connected agent in Studio, and generate to see progress and the file tree.
> [!NOTE]
> With a CLI or Docker agent, generation runs in your environment. Studio receives plugin settings, the project path, progress, generated file paths, and a hash of each generated file. The agent never uploads a local spec. With `--allow-read`, Studio can read generated file contents and the spec as Kubb parsed it. Writing files needs `--allow-write`, and editing `kubb.config.ts` needs `--allow-config-edit`.
## Review and save generated files
To view file contents and diffs, then write generated files to disk, connect with:
```shell [Terminal]
kubb studio --allow-read --allow-write
```
With no permissions granted, Kubb leaves your output folder alone and Studio sees file paths and progress only. The agent keeps copies of recent generations in `node_modules/.cache/kubb`. The CLI remembers permission answers per project. See [Options](/docs/5.x/reference/commands/studio#options) for `--allow-config-edit`, `--allow-exec`, and the other flags.
## Give your AI tools your API
On the Pro plan, Studio turns an agent's OpenAPI spec into a plugin for Claude Code, Cursor, and Codex. The plugin holds skills that list the API's servers, authentication, operations, and schemas. Your organization gets one plugin marketplace, with one plugin per published agent.
1. Connect the agent with `--allow-read` and run a generation. Studio reads the parsed spec of the latest successful generation.
2. In Studio, open **Settings › your organization › AI**, select **Publish an agent**, and choose the agent.
3. Create a registry key under **Settings › Developers › Tokens**. Git asks for it as the password the first time; any username works.
4. Add the marketplace once with your tool, then install the plugin for each API:
:::code-group{sync="ai-tool"}
```shell [Claude Code]
claude plugin marketplace add https://kubb.studio/plugins/.git
claude plugin install @
```
```shell [Cursor]
agent plugin marketplace add https://kubb.studio/plugins/.git
# Then start the Cursor CLI, run /plugin, and install the plugin from the Marketplace tab.
```
```shell [Codex]
codex plugin marketplace add https://kubb.studio/plugins/.git
# Then start codex, run /plugins, and select Install plugin.
```
:::
Cursor and Codex install a plugin from their plugin browser, not with a command. Studio shows the exact commands for each plugin. Republish the agent after the spec changes, then update the marketplace in your tool.
> [!NOTE]
> Plans without AI plugins see the AI page locked. A registry key in the URL, such as `https://kubb:@kubb.studio/...`, works in CI but ends up in shell history and logs.
## Keep an agent running in the background
Start the connection from your project directory:
```shell [Terminal]
kubb studio start --allow-read
```
Complete pairing and permission prompts if this is the first connection. Check that the worker is connected:
```shell [Terminal]
kubb studio status
```
To end the background connection, run:
```shell [Terminal]
kubb studio stop
```
See [Background connection](/docs/5.x/reference/commands/studio#background-connection) for worker states, logs, and restart behavior.
> [!IMPORTANT]
> Without a TTY the CLI skips the permission prompts, so pass the permission flags the run needs. In CI it does not pair either, so use `kubb studio snapshot` with a CI API key there.
---
- **Page:** Generate with Nuxt · Kubb
- **Source:** https://kubb.dev/docs/5.x/integrations/nuxt
- **Description:** Run Kubb code generation during Nuxt builds.
# Generate with Nuxt
> [!IMPORTANT]
> This integration generates during builds only. Run `kubb generate` before starting the development server.
::steps{level="2"}
## Install Kubb and your output plugins
Follow the [installation guide](/docs/5.x/how-to/installation) to add Kubb and the plugins your output needs. The integration ships with `kubb` as `unplugin-kubb`.
## Configure the integration
Import your shared `kubb.config.ts` and pass it to the integration. The `config` must be a single object, not the array or function forms `defineConfig` accepts. Run the build command of your tool to generate the files.
```typescript [nuxt.config.ts]
import config from './kubb.config'
export default defineNuxtConfig({
modules: [['kubb/nuxt', { config }]],
})
```
> [!NOTE]
> Bundler integrations apply fewer defaults than the CLI: no Markdown parser, no reporters, and no `output.postGenerate` commands. Use the CLI when you need them. See [Defaults](/docs/5.x/reference/configuration#defaults).
::
---
- **Page:** Generate with webpack · Kubb
- **Source:** https://kubb.dev/docs/5.x/integrations/webpack
- **Description:** Run Kubb code generation during webpack builds.
# Generate with webpack
::steps{level="2"}
## Install Kubb and your output plugins
Follow the [installation guide](/docs/5.x/how-to/installation) to add Kubb and the plugins your output needs. The integration ships with `kubb` as `unplugin-kubb`.
## Configure the integration
Import your shared `kubb.config.ts` and pass it to the integration. The `config` must be a single object, not the array or function forms `defineConfig` accepts. Run the build command of your tool to generate the files.
```typescript [webpack.config.ts]
import kubb from 'kubb/webpack'
import config from './kubb.config'
export default {
plugins: [kubb({ config })],
}
```
> [!NOTE]
> Bundler integrations apply fewer defaults than the CLI: no Markdown parser, no reporters, and no `output.postGenerate` commands. Use the CLI when you need them. See [Defaults](/docs/5.x/reference/configuration#defaults).
::
---
- **Page:** Generate with Rspack · Kubb
- **Source:** https://kubb.dev/docs/5.x/integrations/rspack
- **Description:** Run Kubb code generation during Rspack builds.
# Generate with Rspack
::steps{level="2"}
## Install Kubb and your output plugins
Follow the [installation guide](/docs/5.x/how-to/installation) to add Kubb and the plugins your output needs. The integration ships with `kubb` as `unplugin-kubb`.
## Configure the integration
Import your shared `kubb.config.ts` and pass it to the integration. The `config` must be a single object, not the array or function forms `defineConfig` accepts. Run the build command of your tool to generate the files.
```typescript [rspack.config.ts]
import kubb from 'kubb/rspack'
import config from './kubb.config'
export default {
plugins: [kubb({ config })],
}
```
> [!NOTE]
> Bundler integrations apply fewer defaults than the CLI: no Markdown parser, no reporters, and no `output.postGenerate` commands. Use the CLI when you need them. See [Defaults](/docs/5.x/reference/configuration#defaults).
::
---
- **Page:** Generate with Vite · Kubb
- **Source:** https://kubb.dev/docs/5.x/integrations/vite
- **Description:** Run Kubb code generation during Vite builds.
# Generate with Vite
> [!IMPORTANT]
> This integration generates during builds only. Run `kubb generate` before starting the development server.
::steps{level="2"}
## Install Kubb and your output plugins
Follow the [installation guide](/docs/5.x/how-to/installation) to add Kubb and the plugins your output needs. The integration ships with `kubb` as `unplugin-kubb`.
## Configure the integration
Import your shared `kubb.config.ts` and pass it to the integration. The `config` must be a single object, not the array or function forms `defineConfig` accepts. Run the build command of your tool to generate the files.
```typescript [vite.config.ts]
import kubb from 'kubb/vite'
import { defineConfig } from 'vite'
import config from './kubb.config'
export default defineConfig({
plugins: [kubb({ config })],
})
```
> [!NOTE]
> Bundler integrations apply fewer defaults than the CLI: no Markdown parser, no reporters, and no `output.postGenerate` commands. Use the CLI when you need them. See [Defaults](/docs/5.x/reference/configuration#defaults).
::
---
- **Page:** Extension model · Kubb
- **Source:** https://kubb.dev/docs/5.x/explanation/extensions
- **Description:** Understand plugin lifecycles, generators, resolvers, macros, and renderers when extending Kubb.
# Extension model
Use an existing [plugin](/extensions/kind/plugins) when it generates the output you need. To add an output or replace a pipeline layer, build on `kubb/kit`, a subpath of the `kubb` package.
## Choose an extension
| You need to change | Extension | Why |
| --- | --- | --- |
| Input format | Adapter | Translate the format into Kubb's shared AST. |
| Schema meaning before generation | Macro | Transform nodes before the plugin processes them. |
| Generated names or paths | Resolver | Keep declarations and imports consistent. |
| Code emitted for a schema type | Printer | Change one output target without changing the input model. |
| A new kind of output | Plugin and generators | Choose the files and content to generate. |
| File syntax or assembly | Parser | Convert emitted nodes into source text. |
| Where files are stored | Storage | Reuse generation with another destination. |
For example, turning a date into a TypeScript `Date` type is a printer customization. Moving model files into a folder is a resolver customization. Changing a schema before several generators consume it calls for a macro. Macros run before printer handlers, so a macro change is visible to every output target while a printer change stays in one.
## Plugins {#plugins}
A plugin factory returns a name, options, and lifecycle hooks. It registers generators and a resolver during `kubb:plugin:setup`, then produces files during generation. Setup can use the setup context through its `ctx` argument or through [composables](/docs/5.x/reference/kit/plugins#setup-context) such as `addGenerator()`, which work in any function setup calls.
::plugin-anatomy
::
### Lifecycle {#lifecycle}
Setup runs once per plugin. Kubb then walks schemas and operations, invokes generators, collects files, and runs output passes. Hooks let a plugin observe or change specific stages.
::lifecycle-timeline
::
The [lifecycle reference](/docs/5.x/reference/kit/hooks) lists the firing order and payloads.
### Dependencies and ordering {#dependencies}
Declared dependencies run before their dependents. Kubb uses `enforce: 'pre'`, normal plugins, then `enforce: 'post'` and declaration order to break ties. Dependencies take priority over `enforce`.
A plugin declares its dependencies as a record keyed by plugin name. A missing required entry fails the run with `KUBB_MISSING_DEPENDENCY` before any plugin runs, and an `optional: true` entry is skipped when its plugin is missing. See [Extensions](/docs/5.x/reference/kit/extensions#dependencies). Resolvers let cooperating plugins read each other's names and paths instead of guessing them.
Post-enforced plugins can process other plugins' emitted files. The built-in barrel plugin uses this to generate re-exports.
## Generators {#generators}
A generator handles `schema` nodes, `operation` nodes, or the complete `operations` batch. Splitting output into generators keeps each task separate. An optional `match` predicate filters schema and operation handlers. It does not filter the batch handler.
Generators return files directly or elements for a renderer. See [Generator reference](/docs/5.x/reference/kit/generators) for handler signatures and context properties.
## Resolvers {#resolvers}
A resolver determines identifiers, filenames, and paths. Generators use the active resolver, and dependent plugins read it to import the correct output.
The plugin's `resolver` option patches its defaults. Use it to rename or relocate output. Use macros to change the underlying schema. See [Override a resolver](/docs/5.x/how-to/resolvers).
## Macros and printers {#macros}
Macros rewrite the AST before generation. Printers turn schema nodes into output for one target, such as TypeScript types or Zod expressions.
Use a macro when the schema meaning changes. Override a printer when one target needs different code. See [Write a macro](/docs/5.x/how-to/macros) and [Override a printer](/docs/5.x/how-to/printers).
## Renderers {#renderers}
Generators can build `FileNode`s with `ast.factory` or return elements that a renderer converts into files. `kubb/jsx` provides the JSX renderer without React. Enable it per generator through `renderer`.
A custom renderer is useful for another templating format. Direct node builders need no renderer. See [JSX reference](/docs/5.x/reference/jsx#renderers).
---
- **Page:** Kubb vs orval, HeyAPI, and openapi-typescript · Kubb
- **Source:** https://kubb.dev/docs/5.x/explanation/comparison
- **Description:** Feature-by-feature comparison of Kubb and Kubb Studio against orval, HeyAPI, and openapi-typescript.
# Kubb vs orval, HeyAPI, and openapi-typescript
Kubb, [orval](https://orval.dev), [HeyAPI](https://heyapi.dev), and [openapi-typescript](https://openapi-ts.dev) all generate code from OpenAPI specs. The tables compare generated outputs, response handling, runtime behavior, and what [Kubb Studio](#kubb-studio) adds around the generator. Each cell was checked against the project's own docs in October 2026.
## Plugin and feature coverage
Legend:
- ✅ Built in, no extra config.
- 🟡 Through a third-party or community plugin.
- 🔶 Supported, but needs extra user code.
- 🛑 Not officially supported.
| Feature | Kubb | orval | HeyAPI | openapi-ts |
| ---------------------------------------------------------------- | :--: | :---: | :------------- | :------------: |
| [OpenAPI 2.0, 3.0, 3.1 input](/extensions/kubb-labs/adapter-oas) | ✅ | ✅ | ✅ | 🔶1 |
| [TypeScript types](/extensions/kubb-labs/plugin-ts) | ✅ | ✅ | ✅ | ✅ |
| [HTTP client (Axios, Fetch)](/extensions/kubb-labs/plugin-axios) | ✅ | ✅ | ✅ | 🔶2 |
| [React Query hooks](/extensions/kubb-labs/plugin-react-query) | ✅ | ✅ | ✅ | 🟡3 |
| [Vue Query composables](/extensions/kubb-labs/plugin-vue-query) | ✅ | ✅ | ✅ | 🛑 |
| [SWR hooks](/extensions/kubb-labs/plugin-swr) | ✅ | ✅ | 🛑6 | 🟡4 |
| [Zod validation schemas](/extensions/kubb-labs/plugin-zod) | ✅ | ✅ | ✅5 | 🛑 |
| [MSW request handlers](/extensions/kubb-labs/plugin-msw) | ✅ | ✅ | ✅7 | 🛑 |
| [Faker.js mock data](/extensions/kubb-labs/plugin-faker) | ✅ | ✅ | ✅7 | 🛑 |
| [Cypress E2E tests](/extensions/kubb-labs/plugin-cypress) | ✅ | 🛑 | 🛑 | 🛑 |
| [MCP server](/extensions/kubb-labs/plugin-mcp) | ✅ | ✅ | 🛑 | 🛑 |
| [Redoc API documentation](/extensions/kubb-labs/plugin-redoc) | ✅ | 🛑 | 🛑 | 🛑 |
| [Barrel index files](/extensions/kubb-labs/plugin-barrel) | ✅ | ✅ | ✅ | 🛑 |
Notes:
1. openapi-typescript reads OpenAPI 3.0 and 3.1 only, so a Swagger 2.0 document has to be up-converted first. Kubb, orval, and HeyAPI accept 2.0 and up-convert it for you.
2. openapi-typescript generates types only. The typed client comes from its `openapi-fetch` runtime, not per-operation code, and `openapi-fetch` is now in [maintenance mode](https://github.com/openapi-ts/openapi-typescript/discussions/2559).
3. openapi-typescript generates no hooks. React Query support comes from the first-party [`openapi-react-query`](https://www.npmjs.com/package/openapi-react-query) runtime, also in maintenance mode.
4. openapi-typescript relies on the community [`swr-openapi`](https://github.com/htunnicliff/swr-openapi) package.
5. HeyAPI also generates Valibot schemas alongside Zod.
6. HeyAPI lists its SWR plugin as planned.
7. HeyAPI marks its MSW and Faker plugins as in progress.
## Type safety and response handling
Kubb exposes a status-discriminated result that narrows response bodies at runtime. The table compares operation typing and error handling.
| Feature | Kubb | orval | HeyAPI |
| ------------------------------------------------------------------------------------------------ | :---: | :------------: | :------------- |
| [Status-discriminated response result](/extensions/kubb-labs/plugin-fetch/guides/error-handling) | ✅ | 🔶1 | 🔶2 |
| Multiple success (2xx) responses | ✅ | ✅ | ✅ |
| Multiple content types per response | ✅ | ✅ | 🛑3 |
| `default` and wildcard (`4XX`, `5XX`) responses | ✅ | ✅4 | ✅ |
| [Typed error responses](/extensions/kubb-labs/plugin-fetch/guides/error-handling) | ✅ | 🔶5 | ✅ |
| [Throw or return the error per call](/extensions/kubb-labs/plugin-fetch/guides/error-handling) | ✅ | 🛑 | ✅ |
| [Zod v4 schemas tied to the types](/extensions/kubb-labs/plugin-zod) | ✅ | ✅ | ✅ |
| Recursive schemas | ✅ | ✅ | ✅ |
| Server-side schema validation | ✅ | ✅ | ✅ |
Notes:
1. Only orval's `fetch` client emits a status-narrowable union. Its axios and query clients return the success type and take the error type on the side.
2. HeyAPI builds a status-keyed type map you index (`Responses[200]`), but the SDK returns a flat `{ data, error }` pair with no `status` to switch on.
3. On `@hey-api/openapi-ts` v0.99.0, a response with both `application/json` and `application/xml` keeps only the JSON shape. Kubb and orval emit a variant per content type.
4. orval expands `4XX` and `5XX` into unions of concrete codes. Kubb and HeyAPI keep the range key.
5. orval types the error body in its `fetch` client, or once you wire `ErrorType` or `override.swr.generateErrorTypes`. Otherwise it stays `Error`.
openapi-typescript is omitted here. It ships no generated client, so the runtime rows do not apply.
## Client runtime
Kubb serializes OpenAPI parameter styles and supports codecs per media type. See [serialization](/extensions/kubb-labs/plugin-fetch/guides/serialization) for the runtime contract.
| Feature | Kubb | orval | HeyAPI |
| ---------------------------------------------------------------------------------------------------------------------------- | :---: | :------------- | :------------- |
| [Parameter styles from the spec](/docs/5.x/reference/serialization#parameter-styles) | ✅ | 🔶1 | 🔶2 |
| Request body serializers (JSON, form-data, urlencoded) | ✅3 | ✅ | ✅ |
| [Pluggable codecs per media type](/extensions/kubb-labs/plugin-fetch/guides/serialization#encode-request-bodies) (XML, YAML) | ✅ | 🛑4 | 🛑4 |
| [Runtime body validation](/extensions/kubb-labs/plugin-fetch/guides/error-handling#validation-failures) | ✅5 | 🔶5 | ✅5 |
| [Server-sent events and streaming](/extensions/kubb-labs/plugin-fetch/guides/server-sent-events) | ✅ | 🔶6 | ✅ |
Notes:
1. Only orval's `fetch` client reads `style` and `explode` from the spec. Its axios and query clients interpolate path parameters directly and leave query encoding to axios or a `qs` config.
2. HeyAPI serializes path parameters per parameter but runs one global query serializer, and does not style header or cookie parameters.
3. All three encode JSON, `multipart/form-data`, and `application/x-www-form-urlencoded`. Kubb also honors the OpenAPI `encoding` object, so a form part can set its own content type and style.
4. orval and HeyAPI expose a single body serializer and one response transformer, so a new media type means replacing them, not registering one.
5. Off by default. Kubb validates request and response bodies through any Standard Schema validator (Zod, valibot, arktype). HeyAPI validates both with Zod or Valibot. orval validates responses only, with Zod.
6. orval streams NDJSON on its `fetch` client but has no server-sent events (`text/event-stream`) support. Kubb and HeyAPI consume SSE.
## Kubb Studio
[Kubb Studio](https://kubb.studio) is the web IDE for Kubb. It runs the same generator through an agent on your machine. The table lists what Studio adds on top of it.
| Feature | Kubb Studio | orval | HeyAPI | openapi-ts |
| ---------------------------------------------------------------------------------------------------------- | :------------: | :------------: | :------------: | :--------: |
| Generation on your own machine | ✅1 | ✅ | ✅ | ✅ |
| [API skills for Claude Code, Cursor, and Codex](/docs/5.x/integrations/studio#give-your-ai-tools-your-api) | ✅2 | 🛑 | 🛑 | 🛑 |
| One AI plugin marketplace for your team | ✅2 | 🛑 | 🛑 | 🛑 |
| [Review added, changed, and removed files](/docs/5.x/integrations/studio#review-and-save-generated-files) | ✅ | 🛑 | 🛑 | 🛑 |
| Edit `kubb.config.ts` from the browser | ✅ | 🛑 | 🛑 | 🛑 |
| [Installable snapshot for every pull request](/docs/5.x/integrations/github-actions) | ✅ | 🛑 | 🛑 | 🛑 |
| Shared agents for the whole team | ✅ | 🛑 | 🛑 | 🛑 |
| Try without installing anything | ✅ | ✅3 | 🟡4 | 🛑 |
Notes:
1. Pair the `kubb studio` CLI or the `kubblabs/kubb-agent` Docker image. The agent never uploads your local spec file. With `--allow-read`, Studio can read the generated files and the spec as Kubb parsed it.
2. On the Pro plan, with an agent started with `--allow-read`. Studio renders the skills from the Kubb AST, so they use the names Kubb generates, and the code your AI tools write calls your generated clients instead of guessing endpoints. A published plugin keeps the servers, operations, and schemas its skills describe.
3. The [orval playground](https://orval.dev/playground) generates code from a spec and config you edit in the browser.
4. HeyAPI links a demo project on StackBlitz. Its hosted [Hey API Platform](https://heyapi.dev/openapi-ts/configuration/input) also stores spec versions as a registry. Studio has no spec registry and keeps no copy of your spec file.
## When not to use Kubb
- You use only a few endpoints that rarely change.
- You have no OpenAPI spec and won't write one.
- You need a non-OpenAPI format now and won't write a custom adapter.
---
- **Page:** Architecture · Kubb
- **Source:** https://kubb.dev/docs/5.x/explanation/architecture
- **Description:** Understand how Kubb converts API specifications into generated files through adapters, the AST, plugins, parsers, and storage.
# Architecture
Kubb separates the input specification, generated content, output syntax, and destination. Each layer has one job:
| Layer | Responsibility |
| --- | --- |
| Adapter | Read the specification and produce an `InputNode`. |
| AST | Describe schemas and operations in a shared tree. |
| Plugin | Run generators that emit `FileNode`s. |
| Parser | Convert emitted nodes into source code. |
| Storage | Persist the generated files. |
::architecture-pipeline
::
## 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](/docs/5.x/tutorials/quickstart) follows this operation using TypeScript and Axios.
## Adapters {#adapters}
An adapter resolves input-specific details, including references, nullability, discriminators, and formats. The default [OpenAPI adapter](/extensions/kubb-labs/adapter-oas) 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.
::flow-diagram{preset="adapter"}
::
## AST {#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.
::ast-tree
::
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](/docs/5.x/reference/kit/ast) for node builders, visitors, and guards.
## Plugins and generators {#plugins}
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](/docs/5.x/explanation/extensions) for how these pieces cooperate.
## Parsers {#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`.
The TypeScript parser prints the banner, the imports, and each source node of a `FileNode` into the file's text:
::flow-diagram{preset="parsers"}
::
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](/docs/5.x/how-to/printers) and [Parser reference](/docs/5.x/reference/kit/parsers).
## Storage {#storage}
Storage separates generation from its destination, so the same build runs on disk for the CLI or in memory for tests. `fsStorage()` writes to disk and `memoryStorage()` keeps results in a `Map`. A custom driver implements the [Storage interface](/docs/5.x/reference/kit/storage#storage-interface) to target another backend.
---
- **Page:** GitHub Actions · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/github-actions
- **Description:** Inputs, outputs, runtime selection, and snapshot comments for kubb-labs/action.
# GitHub Actions
The `kubb-labs/action@v0` action generates and publishes a Studio snapshot. See [Publish snapshots from CI](/docs/5.x/integrations/github-actions) for a workflow.
## Inputs
| Input | Default | Description |
| ------------------- | --------------------- | ----------------------------------------------------------------------- |
| `token` | | Organization CI API key. Required. |
| `github-token` | ${{ github.token }} | Token that opens the init pull request and writes the snapshot comment. |
| `working-directory` | `.` | Directory holding the Kubb config and the package. |
| `config` | `kubb.config.ts` | Path to the config file, relative to `working-directory`. |
## Outputs
| Output | Description |
| ----------------- | -------------------------------------------- |
| `snapshot-id` | ID Studio stored the snapshot under. |
| `package-name` | Name of the generated package. |
| `package-version` | Version of the generated package. |
| `tarball-url` | URL of the generated tarball. |
| `integrity` | SHA-512 integrity of the tarball. |
| `agent-url` | Studio URL of the CI agent that holds the snapshot. |
| `files-added`, `files-changed`, `files-removed` | Generated files added, changed, and removed since the previous snapshot on the pull request. |
## Kubb version
The action runs `kubb studio snapshot` with the Kubb version installed in the repository, so the snapshot matches the version your config and plugins are built against. A local install must be Kubb 5.6.2 or later. Without one, the action uses the latest Kubb 5 release.
## Pull requests and branches
Each pull request reuses one CI agent and one comment. Each branch reuses one CI agent and gets no comment. The action also:
- Skips pull requests from forks, because GitHub hides secrets from them.
- Deletes the pull request's CI agent when the pull request closes.
- Opens a `kubb/init-*` pull request and stops when the config file is missing.
## What the comment shows
Below the install command, the comment lists which generated files changed:
| Section | Compared with |
| --- | --- |
| Changes against `main` | The latest snapshot of the base branch, from the `push` trigger |
| Changes since `abc1234` | The previous snapshot on the same pull request |
A failed snapshot shows its error in the comment.
## Environment variables
| Variable | Default | Description |
| ----------------- | --------------------- | ----------------------------------------- |
| `KUBB_STUDIO_URL` | `https://kubb.studio` | Studio URL for a self-hosted deployment. |
---
- **Page:** Configuration · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/configuration
- **Description:** Reference for kubb.config.ts with every option, default and example for the Kubb v5 UserConfig.
# Configuration
`kubb.config.ts` drives a Kubb run. The file default-exports a `defineConfig` call. Pass it an object, a function that returns one, or an array of configs.
```typescript twoslash [kubb.config.ts]
import { defineConfig } from 'kubb/config'
export default defineConfig({
name: 'petStore',
input: './petStore.yaml',
output: { path: './src/gen' },
})
```
## Config formats
### Single config object
Export an object as in the example above. `defineConfig` also accepts a Promise of a config.
### Config function
Pass a function when the config depends on the run context, such as `watch` or `logLevel`:
```typescript twoslash [kubb.config.ts]
import { defineConfig } from 'kubb/config'
export default defineConfig(({ watch, logLevel }) => ({
name: 'petStore',
input: './petStore.yaml',
output: { path: './src/gen', clean: !watch },
}))
```
The function receives this context:
| | Type | Description |
| ----------: | :--- | :---------- |
| `input` | `string` | Positional input from `kubb generate `. Overrides `config.input` when set. |
| `watch` | `boolean` | `true` in watch mode. |
| `logLevel` | `'silent' \| 'info' \| 'verbose'` | Current log level. |
| `config` | `string` | Path to the config file in use. |
| `reporters` | `Array` | Reporters selected via `--reporter`, overriding `config.reporters`. |
### Multiple configurations (array)
Pass an array to generate from several specs in one command:
```typescript twoslash [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { pluginTs } from '@kubb/plugin-ts'
export default defineConfig([
{
name: 'petStore',
input: './petStore.yaml',
output: { path: './src/gen/petStore' },
plugins: [pluginTs()],
},
{
name: 'stripe',
input: './stripe.yaml',
output: { path: './src/gen/stripe' },
plugins: [pluginTs()],
},
])
```
A config function can return an array to combine both forms.
## Defaults {#defaults}
`defineConfig` from `kubb/config` and `createKubb` from `kubb` fill in these fields when you omit them. The bare `@kubb/core` engine applies none of them.
| Field | Default |
| ---------------- | ------- |
| `root` | `process.cwd()` |
| `adapter` | `adapterOas()` from the bundled [OpenAPI adapter](/extensions/kubb-labs/adapter-oas) |
| `parsers` | `[parserTs(), parserTsx(), parserMd()]` |
| `reporters` | `[cli, json, file, html]` |
| `plugins` | `pluginBarrel()` appended when not already present |
| `storage` | `fsStorage()` |
| `output.barrel` | `false`, so `pluginBarrel` generates nothing until you opt in |
| `output.format` | `false` |
| `output.lint` | `false` |
| `output.defaultBanner` | `'simple'` |
Bundler integrations apply a smaller set: no `parserMd` and no reporters. See [Build tools](/docs/5.x/integrations/overview#build-tools).
## Top-level options
::field-group
### `name`
:::field{type="string"}
A name for this config. The CLI prints it as `Generating ...`.
:::
### `input`
:::field{type="string | Record"}
Where Kubb reads your spec: a local file path, a URL, inline OpenAPI content as a JSON or YAML string, or an already-parsed object. Kubb detects which one you gave it. Required when an adapter is configured. Omit it in plugin-only mode, when there is no `adapter`.
A string that starts with `{` or `[`, spans multiple lines, or opens with a YAML `openapi:` or `swagger:` key is read as inline content. Anything else is a file path or a URL, and a relative path resolves against the config file.
```typescript twoslash [kubb.config.ts]
import { defineConfig } from 'kubb/config'
export default defineConfig({
// a path, a URL, an inline JSON/YAML string, or a parsed object
input: './petStore.yaml',
output: { path: './src/gen' },
})
```
:::
### `output`
Controls where and how files are written.
#### `output.path`
:::field{type="string" required}
Directory for generated files, absolute or relative to `root`.
:::
#### `output.mode`
:::field{type="'file' | 'directory'"}
How a plugin consolidates its code into files. Set it on a plugin's `output`, not on the root `output`.
Default: follows the shape of `output.path`.
`'file'` writes everything into a single file, so `output.path` must include the extension (`'types.ts'`). `'directory'` writes one file per operation or schema under `output.path`. Pair `'directory'` with `group` to split the output into per-tag or per-path subdirectories.
You rarely need to set this. Leave it out and Kubb reads `output.path`: a path with an extension means one file, a path without one means a directory. Every plugin ships an extensionless default such as `'types'` or `'clients'`, so `pluginTs()` writes a directory without any configuration.
```typescript twoslash [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { pluginTs } from '@kubb/plugin-ts'
import { pluginAxios } from '@kubb/plugin-axios'
export default defineConfig({
input: './petstore.yaml',
output: { path: './src/gen' },
plugins: [
pluginTs({ output: { path: 'types.ts' } }),
pluginAxios({ output: { path: 'clients', mode: 'directory' }, group: { type: 'tag' } }),
],
})
```
This writes every type into `src/gen/types.ts` and one client file per operation, grouped by tag (`src/gen/clients/pet/`, `src/gen/clients/store/`).
> [!TIP]
> `group` works with the inferred directory mode, no `mode` needed. Set `mode: 'directory'` yourself only to override the inference, such as a directory name that carries a dot (`path: 'clients.v2'`). An explicit `mode: 'file'` still forbids `group` and stops the build with a `KUBB_INVALID_PLUGIN_OPTIONS` error, because a single file has nothing to group.
:::
#### `output.clean`
:::field{type="boolean"}
Wipe `output.path` before regenerating.
Default: `false`.
> [!WARNING]
> Only use `clean: true` with a dedicated output folder. Kubb removes the entire directory.
:::
#### `output.format`
:::field{type="'auto' | 'prettier' | 'biome' | 'oxfmt' | false"}
Formatter to run on every generated file.
Default: `false`.
`'auto'` detects the first formatter it finds ([oxfmt](https://oxc.rs) then [Biome](https://biomejs.dev) then [Prettier](https://prettier.io)). A named tool forces that one. `false` skips formatting. Kubb reads your local `.prettierrc` or `biome.json`.
:::
#### `output.lint`
:::field{type="'auto' | 'eslint' | 'biome' | 'oxlint' | false"}
Linter to run after generation.
Default: `false`.
`'auto'` detects the first linter it finds ([oxlint](https://oxc.rs) then [Biome](https://biomejs.dev) then [ESLint](https://eslint.org)). A named tool forces that one. `false` skips linting.
:::
#### `output.postGenerate`
:::field{type="Array"}
Shell commands to run after the generated files are formatted and linted, such as a type check or a custom script. Commands run from the `root` directory, in sequence. Pass a command string, or `{ name, command }` to label a step in the CLI output.
```typescript twoslash [kubb.config.ts]
import { defineConfig } from 'kubb/config'
export default defineConfig({
input: './petStore.yaml',
output: {
path: './src/gen',
postGenerate: [{ name: 'types', command: 'npm run typecheck' }, 'biome check --write ./src/gen'],
},
})
```
:::
#### `output.barrel`
:::field{type="{ type: 'all' | 'named' } | false"}
Behavior of the root `index.ts` barrel file at `output.path`, and the default every plugin inherits.
Default: `false`.
`{ type: 'named' }` re-exports each symbol by name, `{ type: 'all' }` writes `export *`. See [`@kubb/plugin-barrel` options](/extensions/kubb-labs/plugin-barrel/options#outputbarrel) for the export styles and the plugin-level `nested` flag, and [Add barrel files](/docs/5.x/how-to/barrel-files) for the setup steps.
:::
#### `output.defaultBanner`
:::field{type="'simple' | 'full' | false"}
Auto-generated banner injected at the top of each file.
Default: `'simple'`.
`'simple'` adds a short "Generated by Kubb" notice. `'full'` adds the notice plus `Source`, `Title`, and `OpenAPI spec version` from the spec. `false` writes no banner.
::::code-group
```typescript [simple]
/**
* Generated by Kubb (https://kubb.dev/).
* Do not edit manually.
*/
```
```typescript [full]
/**
* Generated by Kubb (https://kubb.dev/).
* Do not edit manually.
* Source: petStore.yaml
* Title: Pet Store
* OpenAPI spec version: 1.0.0
*/
```
```typescript [false]
// no banner
```
::::
:::
#### `output.banner`
:::field{type="string | ((meta: BannerMeta) => string)"}
Text prepended to every file a plugin generates. Set it on an individual plugin. The root `output` exposes only [`output.defaultBanner`](#outputdefaultbanner). Use it for license headers, lint-disable comments, or framework directives like `'use server'`.
A string applies to every file the plugin generates, including barrel (`index.ts`) and group aggregation (`[dir]/[dir].ts`) re-export files. A function runs once per file and receives a `BannerMeta`, so you can vary the banner per file or return an empty string to skip it.
`BannerMeta` extends the document `InputMeta` (`title`, `description`, `version`, …) with per-file context:
| | | |
| -----------: | :-------- | :------------------------------------------------------- |
| `filePath` | `string` | Full output path of the file being generated. |
| `baseName` | `string` | File name only, for example `stocks.ts`. |
| `isBarrel` | `boolean` | `true` for `index.ts` re-export barrels. |
| `isAggregation` | `boolean` | `true` for group `[dir]/[dir].ts` aggregation files. |
> [!NOTE]
> Barrel `index.ts` files stay banner-free by default. They get a banner only when the plugin sets `output.banner`, at which point the function runs with `isBarrel: true`.
:::
#### `output.footer`
:::field{type="string | ((meta: BannerMeta) => string)"}
Text appended to the end of every file a plugin generates. Mirror of [`output.banner`](#outputbanner), with the same `string | ((meta: BannerMeta) => string)` type.
:::
### `plugins`
:::field{type="Array"}
Array of Kubb plugins. Dependencies run first. A plugin that requires one missing from this array fails the run with `KUBB_MISSING_DEPENDENCY`.
:::
### `adapter`
:::field{type="Adapter"}
Adapter that converts your input into the universal AST. With `defineConfig` from the `kubb` package this defaults to `adapterOas()` from [`@kubb/adapter-oas`](/extensions/kubb-labs/adapter-oas).
See the [Adapter concept](/docs/5.x/explanation/architecture#adapters) for the full picture.
Default: `adapterOas()` (included with `kubb`).
Pass options to customize the adapter:
```typescript twoslash [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { adapterOas } from '@kubb/adapter-oas'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
adapter: adapterOas({ validate: true }),
})
```
:::
### `parsers`
:::field{type="Array"}
Array of parsers that turn the in-memory file representation into source code. Each parser declares which file extensions it handles through `extNames`.
See the [Parser concept](/docs/5.x/explanation/architecture#parsers) and [`@kubb/parser-ts`](/extensions/kubb-labs/parser-ts) for the built-in parsers.
Default: `[parserTs(), parserTsx(), parserMd()]` (included with `kubb`).
Import parsers explicitly to override the default set:
```typescript twoslash [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { parserTs, parserTsx } from '@kubb/parser-ts'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
parsers: [parserTs(), parserTsx()],
})
```
:::
### `storage`
:::field{type="Storage"}
Storage driver that persists generated files. Defaults to `fsStorage()` (filesystem).
See the [Storage concept](/docs/5.x/explanation/architecture#storage) for the built-in drivers and how to write a custom backend.
Default: `fsStorage()`.
```typescript twoslash [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { memoryStorage } from 'kubb/kit'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
storage: memoryStorage(),
})
```
:::
### `root`
:::field{type="string"}
Project root, absolute or relative to the config file location.
Default: `process.cwd()`.
:::
### `reporters`
:::field{type="Array"}
Reporters available to the run, registered as instances. `defineConfig` registers the built-in `cli`, `json`, `file`, and `html` reporters by default. The HTML reporter remains opt-in: select it with [`--reporter html`](/docs/5.x/reference/commands/generate#reporters). The CLI [`--reporter`](/docs/5.x/reference/commands/generate#reporters) flag selects reporters by name and defaults to `cli`. See that page for details about each reporter.
Default: `[cli, json, file, html]`.
:::
::
::studio-cta{source="configuration-reference"}
::
---
- **Page:** Extension registry · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/registry
- **Description:** Reference for the Kubb extension registry protocol at kubb.dev/registry, its index and detail documents, registry ids, records that pin one npm version or GitHub release, and how to host your own registry.
# Extension registry
The Kubb extension registry lists reviewed plugins, adapters, and parsers. Each entry pins one npm version or one GitHub release. [`kubb add`](/docs/5.x/reference/commands/add), [`kubb update`](/docs/5.x/reference/commands/update), [`kubb list`](/docs/5.x/reference/commands/list), kubb.dev, and Kubb Studio read it.
The base URL is `https://kubb.dev/registry`. The registry is a set of plain static JSON documents:
- Served as `application/json`, with CORS allowed, so any site or tool can read them.
- Answered directly, never through a redirect.
- Cached for 10 minutes (`cache-control: public, max-age=600`).
[kubb-labs/registry](https://github.com/kubb-labs/registry) builds the documents on every merge and once a day.
## Registry ids
An id is `/`, such as `kubb-labs/plugin-zod`:
- `` is the GitHub owner of the source repository, in lowercase.
- `` is the package name without its scope. `@kubb/plugin-zod` gives `plugin-zod`.
- Both parts match `[a-z0-9]+(?:-[a-z0-9]+)*`: lowercase letters and digits joined by single hyphens.
The CLI accepts a bare `` and reads it as `kubb-labs/`. An entry owned by `kubb-labs` has `type: "official"`. Every other entry is `community`.
## `GET /index.json` {#index}
Returns every extension in the registry:
```typescript
type RegistryIndex = {
version: 1
generatedAt: string
extensions: Array
}
```
The CLI rejects an index whose `version` is not `1`. It skips an entry that fails validation and keeps the rest.
## `GET //.json` {#detail}
Returns one extension and the docs its pinned version ships:
```typescript
type RegistryDetail = RegistryEntry & {
overview: string | null
options?: string | null
guides?: Array
}
type RegistryGuide = {
id: string
title: string
description: string
content: string
}
```
The fields come from the package's [`docs/` folder](/docs/5.x/reference/kit/extension-docs):
- `overview` is the Markdown of `docs/overview.md`, or the overview the reviewer wrote.
- `options` is the Markdown of `docs/options.md`, or `null` when the package ships none.
- `guides` holds one entry per `docs/guides/.md`, in file name order. `id` is the file name without `.md`, `title` is the first `#` heading, `description` is the first paragraph after it, and `content` is the whole file.
Read a missing `options` as `null` and a missing `guides` as `[]`. An unknown id answers 404, and `kubb add` reports `"" is not in the registry at .`
## `RegistryEntry` {#registry-entry}
`@kubb/core` exports the `RegistryEntry`, `RegistryIndex`, `RegistryDetail`, and `RegistryGuide` types.
::field-group
### `id`
:::field{type="string" required}
The registry id, such as `kubb-labs/plugin-zod`.
:::
### `kind`
:::field{type="'plugin' | 'adapter' | 'parser'" required}
The extension kind. It always equals `manifest.kind`.
:::
### `type`
:::field{type="'official' | 'community'" required}
`official` when the owner is `kubb-labs`, otherwise `community`.
:::
### `artifact`
:::field{type="RegistryArtifact" required}
The install pin the registry approved. It has one of two kinds:
- `{ kind: 'npm', package, version }`: `kubb add` and `kubb update` install `@`.
- `{ kind: 'github', package, version, owner, repo, tag, commit }`: a release of a package at the repository root. `kubb add` and `kubb update` install `github:/#`. `package` is the `name` in its `package.json`, and `tag` names `version`.
:::
### `repository`
:::field{type="{ url: string }"}
The source on GitHub. An npm artifact may point at the package folder. A GitHub artifact uses the repository root.
:::
### `manifest`
:::field{type="ExtensionManifest" required}
The [`kubb-extension.json`](/docs/5.x/reference/kit/manifest) of the pinned version, with the reviewer's main category and listing overrides applied. An official version released before manifests ships none. The index leaves out that extension until a version that ships a manifest is pinned.
:::
### `stats`
:::field{type="{ downloads?: number; weekly?: number; stars?: number }"}
Download and star counts, when known.
:::
### `submittedAt`
:::field{type="string" required}
When the extension was submitted. It never changes.
:::
### `publishedAt`
:::field{type="string" required}
When the first version was approved and listed. It never changes.
:::
### `reviewedAt`
:::field{type="string" required}
When the pinned version was approved. Every version bump moves it.
:::
::
Timestamps are UTC, to the second, such as `2026-10-12T20:00:00Z`.
The CLI skips an entry unless `id` is a full `/`, `artifact` is an npm or GitHub pin with an exact semver version, and `manifest` is valid with the entry's `kind`. A detail document's `id` must equal the id the CLI asked for.
## Records
The reviewed records live in [kubb-labs/registry](https://github.com/kubb-labs/registry) at `extensions//.json`. The registry's build turns them into the documents above. Merging a record approves its pinned version.
```json [extensions/kubb-labs/plugin-zod.json]
{
"$schema": "https://kubb.dev/schemas/registry-record.json",
"id": "kubb-labs/plugin-zod",
"artifact": { "kind": "npm", "package": "@kubb/plugin-zod", "version": "5.4.4" },
"repository": { "url": "https://github.com/kubb-labs/plugins/tree/main/packages/plugin-zod" },
"submittedAt": "2026-10-12T20:11:53Z",
"submittedBy": "stijnvanhulle",
"publishedAt": "2026-10-12T20:11:53Z",
"reviewedAt": "2026-10-12T20:11:53Z",
"categories": ["validation"]
}
```
| Field | Written by | Meaning |
| --- | --- | --- |
| `id`, `artifact`, `repository`, `submittedAt`, `publishedAt`, `reviewedAt` | Bot | As in [`RegistryEntry`](#registry-entry). `id` must equal the file path. |
| `submittedBy` | Bot | The GitHub user who opened the submission. |
| `categories` | Reviewer | Category slugs. The first is the main one and replaces the manifest's `category`. |
| `listing` | Reviewer | Optional overrides for `displayName`, `description`, `tags`, and `icon`. |
The record JSON Schema is [`https://kubb.dev/schemas/registry-record.json`](https://kubb.dev/schemas/registry-record.json). To add a record, follow [Submit to the registry](/docs/5.x/how-to/submit-to-the-registry).
### Categories
| Slug | Use for |
| --- | --- |
| `types` | Generate TypeScript types and interfaces. |
| `validation` | Validate data at runtime with schemas. |
| `client` | Generate HTTP clients that call the API. |
| `framework` | Generate hooks and composables for UI frameworks. |
| `mocks` | Generate mock data and mock servers. |
| `testing` | Generate tests and test helpers. |
| `documentation` | Generate API documentation. |
| `ai` | Expose the API to AI agents and tools. |
| `output` | Shape the generated files, such as barrel files. |
| `openapi` | Read OpenAPI and Swagger specs. |
| `typescript` | Print generated code as TypeScript. |
| `docs` | Print generated code as Markdown. |
## Host your own registry
Serve the same two documents from any static host, then point the CLI at it with `KUBB_REGISTRY`. To build them from your own records, fork [kubb-labs/registry](https://github.com/kubb-labs/registry), replace `extensions/`, and run `pnpm build`. The `dist/` folder is the whole registry.
```shell [Terminal]
KUBB_REGISTRY=https://registry.example.com kubb add acme/plugin-graphql
```
With that base URL, the CLI reads `https://registry.example.com/index.json` and `https://registry.example.com/acme/plugin-graphql.json`. `KUBB_REGISTRY` must start with `http://` or `https://`, and trailing slashes are removed.
Your documents must follow the shapes on this page, and `index.json` must set `version: 1`. Answer 404 for an unknown id. Studio always reads the kubb.dev index, so a private registry changes what the CLI installs, not what Studio lists.
---
- **Page:** HTTP serialization · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/serialization
- **Description:** Default parameter styles and serialized values for generated Fetch and Axios clients.
# HTTP serialization
Fetch and Axios clients use the OpenAPI operation's serialization metadata to encode path, query, header, and cookie parameters.
## Parameter styles
### Query
Query parameters default to the `form` style. Arrays explode into repeated keys unless the spec
says otherwise, and `spaceDelimited`, `pipeDelimited`, and `deepObject` change how arrays and
objects collapse.
| Style | `explode` | Input | Result |
| ------------------ | --------- | ------------------ | ----------------- |
| `form` (default) | `true` | `{ id: [3, 4, 5] }` | `id=3&id=4&id=5` |
| `form` | `false` | `{ id: [3, 4, 5] }` | `id=3,4,5` |
| `spaceDelimited` | `false` | `{ id: [3, 4, 5] }` | `id=3%204%205` |
| `pipeDelimited` | `false` | `{ id: [3, 4, 5] }` | `id=3\|4\|5` |
| `deepObject` | `n/a` | `{ a: { b: 1 } }` | `a%5Bb%5D=1` |
With `explode: true`, `spaceDelimited` and `pipeDelimited` fall back to repeated keys like `form`,
so the delimiter only shows with `explode: false`.
### Path
Path parameters default to the `simple` style, which emits the bare value. `label` prefixes a
`.` and `matrix` prefixes a `;name=` segment. The results below are the serialized segment for a
parameter named `id`.
| Style | `explode` | Input | Result |
| ------------------ | --------- | ---------------- | ------------------ |
| `simple` (default) | `false` | `[3, 4, 5]` | `3,4,5` |
| `label` | `true` | `[3, 4, 5]` | `.3.4.5` |
| `matrix` | `true` | `[3, 4, 5]` | `;id=3;id=4;id=5` |
| `simple` | `false` | `{ x: 1, y: 2 }` | `x,1,y,2` |
### Header and cookie
Header parameters use the `simple` style and cookie parameters use the `form` style. Both fix the
style and only let `explode` vary, so the metadata for these locations carries `explode` alone.
Header values are sent as-is, and cookie values are URL-encoded into a single `Cookie` header.
| Location | `explode` | Input | Result |
| -------- | --------- | -------------------------------- | ----------------------- |
| header | `false` | `[3, 4]` | `X-Ids: 3,4` |
| header | `true` | `{ role: 'admin' }` | `X-Filter: role=admin` |
| cookie | `false` | `{ session: 'abc', ids: [1, 2] }` | `session=abc; ids=1,2` |
| cookie | `true` | `{ ids: [1, 2] }` | `ids=1; ids=2` |
For custom serializers, body codecs, response decoding, and validation, see [Configure serialization](/extensions/kubb-labs/plugin-fetch/guides/serialization).
---
- **Page:** JSX renderer · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/jsx
- **Description:** The kubb/jsx surface backed by @kubb/renderer-jsx. jsxRenderer, the built-in components, and the JSX runtime for component-based code generation.
# JSX renderer
`kubb/jsx` is Kubb's JSX-based renderer, an alternative to building files with the `ast.factory` node builders from [`kubb/kit`](/docs/5.x/reference/kit). It provides a JSX runtime and a set of built-in components so a generator can emit files and markdown through JSX.
## Renderers {#renderers}
A renderer turns the elements a generator returns into `FileNode`s. Set it on a generator through its `renderer` field (`renderer: jsxRenderer`). Leave the field unset, or pass `renderer: null`, when the generator builds `FileNode`s with `ast.factory` directly.
`jsxRenderer` does not use React. Components run as plain functions, so hooks and suspense are not available.
`createRenderer` from `kubb/kit` takes a builder function and returns a factory that produces a `Renderer`. Use it only for a different templating format.
## Setup
Point your `tsconfig.json` at the `kubb/jsx` runtime so JSX syntax compiles against its components instead of React's:
```json [tsconfig.json]
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "kubb/jsx"
}
}
```
With that in place, `.tsx` files in the plugin resolve `jsx-runtime` and `jsx-dev-runtime` from `kubb/jsx` automatically.
## `jsxRenderer()`
`jsxRenderer` creates a renderer instance with two members, `render` and `files`. Call `render` with a JSX element, then read the generated files back off `files`.
```tsx twoslash [render.tsx]
import { jsxRenderer } from 'kubb/jsx'
import { File, Function, Type } from 'kubb/jsx'
const renderer = jsxRenderer()
await renderer.render(
{'{ id: number; name: string }'}
{"return fetch('/pets')"}
,
)
const files = renderer.files
```
## Built-in components
Core components declare an output file and its imports, exports, and source blocks. JavaScript components emit TypeScript declarations. Markdown components emit markdown. `Jsx` embeds a raw JSX string.
| Component | Category | Emits |
| --- | --- | --- |
| [`File`](#file) | Core | File entry |
| [`File.Source`](#file-source) | Core | Source block |
| [`File.Import`](#file-import) | Core | Import statement |
| [`File.Export`](#file-export) | Core | Export statement |
| [`Const`](#const) | JavaScript | TypeScript |
| [`Function`](#function) | JavaScript | TypeScript |
| [`Function.Arrow`](#function-arrow) | JavaScript | TypeScript |
| [`Type`](#type) | JavaScript | TypeScript |
| [`Callout`](#callout) | Markdown | Markdown |
| [`Frontmatter`](#frontmatter) | Markdown | Markdown |
| [`Heading`](#heading) | Markdown | Markdown |
| [`List`](#list) | Markdown | Markdown |
| [`Paragraph`](#paragraph) | Markdown | Markdown |
| [`Jsx`](#jsx-component) | JSX | Raw JSX |
### Core
`File` is the container. Its members `File.Source`, `File.Import`, and `File.Export` attach source blocks, imports, and exports to it.
#### `File` {#file}
Declares a generated output file. Pass both `baseName` and `path` to register a file entry. Omit both to render the children inline without creating a file.
| Prop | Type | Description |
| --- | --- | --- |
| `baseName` | `` `${string}.${string}` `` | File name with extension, such as `petStore.ts`. |
| `path` | `string` | Fully qualified path to the generated file. |
| `meta?` | `object \| null` | Metadata attached to the file node for plugins to read. |
| `banner?` | `string \| null` | Text prepended before the source blocks. |
| `footer?` | `string \| null` | Text appended after the source blocks. |
| `copy?` | `string \| null` | Absolute path to copy verbatim into the output, bypassing the parser. |
| `children?` | `KubbReactNode` | Source blocks, imports, and exports that make up the file. |
```tsx
{`export type Pet = { id: number; name: string }`}
```
#### `File.Source` {#file-source}
Marks a block of source text that belongs to the enclosing `File`. The children are the source string.
| Prop | Type | Description |
| --- | --- | --- |
| `name?` | `string \| null` | Identifies the source for deduplication and barrel generation. |
| `isExportable?` | `boolean \| null` | Prepend the `export` keyword. |
| `isIndexable?` | `boolean \| null` | Include the source in barrel and index generation. |
| `isTypeOnly?` | `boolean \| null` | Mark the source as a type-only export. |
| `children?` | `KubbReactNode` | Source text of the block. |
```tsx
{`export type PetId = string`}
```
#### `File.Import` {#file-import}
Declares an import for the enclosing `File`. The renderer emits it at the top of the generated file.
| Prop | Type | Description |
| --- | --- | --- |
| `name` | `string \| Array` | Binding to import. A string for a default or namespace import, an array for named imports. |
| `path` | `string` | Module specifier to import from. |
| `root?` | `string \| null` | Root used to resolve the import path relative to the file. |
| `isTypeOnly?` | `boolean \| null` | Emit `import type`. |
| `isNameSpace?` | `boolean \| null` | Emit `import * as name`. |
```tsx
// import { useState } from 'react'
// import * as z from 'zod'
```
#### `File.Export` {#file-export}
Declares an export for the enclosing `File`. The renderer emits it at the top of the generated file.
| Prop | Type | Description |
| --- | --- | --- |
| `name?` | `string \| Array \| null` | Binding to export. Omit for a wildcard export. |
| `path` | `string` | Module specifier to export from. |
| `isTypeOnly?` | `boolean \| null` | Emit `export type`. |
| `asAlias?` | `boolean \| null` | Emit `export * as name`. |
```tsx
// export { Pet } from './models/petStore'
// export type * from './models/petStore'
```
### JavaScript
The JavaScript components emit TypeScript declarations. Nest them inside a `File.Source` so the renderer writes them into a `.ts` file.
#### `Const` {#const}
Generates a TypeScript constant declaration. The children are the initializer expression.
| Prop | Type | Description |
| --- | --- | --- |
| `name` | `string` | Identifier of the constant. |
| `export?` | `boolean \| null` | Prepend the `export` keyword. |
| `type?` | `string \| null` | Type annotation written after `const name:`. |
| `asConst?` | `boolean \| null` | Append `as const` after the initializer. |
| `JSDoc?` | `JSDoc \| null` | JSDoc block prepended to the declaration. |
| `children?` | `KubbReactNode` | Initializer expression. |
```tsx
{`z.object({ id: z.number() })`}
// export const petSchema: z.ZodType = z.object({ id: z.number() })
```
#### `Function` {#function}
Generates a TypeScript function declaration. The children are the function body.
| Prop | Type | Description |
| --- | --- | --- |
| `name` | `string` | Identifier of the function. |
| `export?` | `boolean \| null` | Prepend the `export` keyword. |
| `default?` | `boolean \| null` | Emit `default` after `export` to make this the default export. |
| `async?` | `boolean \| null` | Emit `async`. Wraps `returnType` in `Promise<…>`. |
| `params?` | `string \| null` | Parameter list written between the parentheses. |
| `generics?` | `string \| Array \| null` | Generic type parameters. An array joins with commas. |
| `returnType?` | `string \| null` | Return type annotation written after `:`. |
| `JSDoc?` | `JSDoc \| null` | JSDoc block prepended to the declaration. |
| `children?` | `KubbReactNode` | Function body. |
```tsx
{'return client.get("/pets/" + petId)'}
// export async function getPet(petId: string): Promise { … }
```
#### `Function.Arrow` {#function-arrow}
Generates an arrow function assigned to a `const`. Takes every `Function` prop plus `singleLine`.
| Prop | Type | Description |
| --- | --- | --- |
| `singleLine?` | `boolean \| null` | Render a braceless expression body instead of a block. |
```tsx
{`n * 2`}
// export const double = (n: number): number => n * 2
```
#### `Type` {#type}
Generates a TypeScript type alias. The children are the type expression. `name` must start with an uppercase letter or the component throws.
| Prop | Type | Description |
| --- | --- | --- |
| `name` | `string` | Identifier of the type alias, starting with an uppercase letter. |
| `export?` | `boolean \| null` | Prepend the `export` keyword. |
| `JSDoc?` | `JSDoc \| null` | JSDoc block prepended to the declaration. |
| `children?` | `KubbReactNode` | Type expression on the right-hand side. |
```tsx
{`string | number`}
// export type PetId = string | number
```
### Markdown
The markdown components each emit their own source block, so they go directly inside a `File` rather than a `File.Source`. Render the file with `parserMd` so it is written as markdown.
```tsx twoslash [docs.tsx]
import { jsxRenderer } from 'kubb/jsx'
import { File, Frontmatter, Heading, Paragraph, List, Callout } from 'kubb/jsx'
const renderer = jsxRenderer()
await renderer.render(
Pets
{'A pet object with an id and a name.'}
Keep the generator hot with kubb generate --watch.
,
)
```
#### `Callout` {#callout}
Renders a GitHub-style alert using the `> [!TYPE]` blockquote syntax.
| Prop | Type | Description |
| --- | --- | --- |
| `type` | `'tip' \| 'note' \| 'important' \| 'warning' \| 'caution'` | Callout kind, mapped to the uppercase label. |
| `title?` | `string \| null` | Title rendered on the marker line. |
| `children` | `string` | Body text. Each line is quoted with `> `. |
```tsx
Breaking change in v6.
// > [!WARNING] Heads up
// > Breaking change in v6.
```
#### `Frontmatter` {#frontmatter}
Emits a YAML frontmatter envelope at the top of a markdown file. Place it as the first child of the `File`.
| Prop | Type | Description |
| --- | --- | --- |
| `data` | `Record` | Object serialized to YAML between `---` fences. |
```tsx
// ---
// title: Pets
// layout: doc
// ---
```
#### `Heading` {#heading}
Renders an ATX-style markdown heading.
| Prop | Type | Description |
| --- | --- | --- |
| `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | Heading depth, matching the number of `#` characters. |
| `children` | `string` | Heading text. |
```tsx
Installation
// ## Installation
```
#### `List` {#list}
Renders a markdown list, one entry per line.
| Prop | Type | Description |
| --- | --- | --- |
| `items` | `ReadonlyArray` | List entries, one per line. |
| `ordered?` | `boolean \| null` | Emit a numbered list. Defaults to a bullet list. |
```tsx
// 1. First
// 2. Second
```
#### `Paragraph` {#paragraph}
Renders a markdown paragraph. Inline markdown passes through verbatim.
| Prop | Type | Description |
| --- | --- | --- |
| `children` | `string` | Paragraph text. |
```tsx
{'A pet object with `id` and `name` fields.'}
```
### JSX
#### `Jsx` {#jsx-component}
Embeds a raw JSX string in the generated source, including fragments. Use it inside a `Function` to emit a component body. The children must be a plain string.
| Prop | Type | Description |
| --- | --- | --- |
| `children?` | `string` | Raw JSX string embedded verbatim. |
```tsx
{'return (\n <>\n Hello\n >\n)'}
```
---
- **Page:** Kit API · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/kit
- **Description:** The kubb/kit reference for authoring plugins, generators, resolvers, renderers, adapters, parsers, and storage backends, plus the ast namespace, Diagnostics, the engine surface, and the testing helpers.
# Kit API
Import authoring APIs from `kubb/kit`, included with the `kubb` package.
## Big concepts
| Concept | Entry point | What it does |
| --------------------------- | -------------------------------------------- | ------------------------------------------------------------------------ |
| [Plugins](./kit/plugins) | `defineExtension` (`kind: 'plugin'`) | The main extension point. Owns file naming, the output folder, and the lifecycle hooks. |
| [Generators](./kit/generators) | `defineGenerator` | Walks the AST and emits files. A plugin registers one or more. |
| [Resolvers](./kit/resolvers) | `createResolver` | Decides file names and output paths. Other plugins read them by name. |
| [Renderers](/docs/5.x/reference/jsx#renderers) | `createRenderer`, `jsxRenderer` | Turns the elements a generator returns into `FileNode`s. |
| [Adapters](./kit/adapters) | `defineExtension` (`kind: 'adapter'`) | Converts an input spec into the universal AST every plugin reads. |
| [Parsers](./kit/parsers) | `defineExtension` (`kind: 'parser'`) | Turns a `FileNode` into the source string written to disk. |
| [Extensions](./kit/extensions) | `defineExtension`, `meta`, `dependencies` | What plugins, adapters, and parsers share: `kind`, identity, compatibility ranges, and plugin dependencies. |
| [Storage](./kit/storage) | `createStorage`, `fsStorage`, `memoryStorage`| Decides where generated files land. |
## Other parts
| Part | Entry point | What it does |
| ------------------------------------------ | -------------------------- | --------------------------------------------------------------- |
| [AST and node builders](./kit/ast) | `ast` | The namespace behind `factory` builders, visitors, guards, macros, and printers. |
| [Engine](./kit/engine) | `createKubb`, `Diagnostics` | The `kubb`-package surface that runs your plugins and the errors it collects. |
| [Lifecycle hooks](./kit/hooks) | `KubbHooks` | Every `kubb:*` hook a build fires, its payload, and when it fires. |
| [Testing](./kit/testing) | `kubb/kit/testing` | Vitest-backed helpers for testing plugins, generators, and adapters. |
| [Extension manifest](./kit/manifest) | `kubb-extension.json` | The file an extension package ships for the registry, `kubb add`, and Studio. |
| [Extension docs](./kit/extension-docs) | `docs/` | The Markdown pages an extension ships for kubb.dev. |
---
- **Page:** Telemetry · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/telemetry
- **Description:** Learn what anonymous usage data Kubb collects, how to opt out, and how the data improves the tool.
# Telemetry
The Kubb CLI collects anonymous command, plugin, and performance data.
> [!IMPORTANT]
> Telemetry is enabled by default. Disable it any time with the `DO_NOT_TRACK` or `KUBB_DISABLE_TELEMETRY` environment variable.
## What is collected
Telemetry includes these fields:
| Field | Description | Example |
| ---------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `command` | CLI command that was run | `"generate"`, `"validate"`, `"mcp"` |
| `kubbVersion` | Kubb CLI version | `"5.0.0"` |
| `nodeVersion` | Node.js major version | `"22"` |
| `runtime` | JavaScript runtime name | `"node"`, `"bun"`, `"deno"` |
| `runtimeVersion` | Runtime major version | `"22"` |
| `platform` | Operating system | `"linux"`, `"darwin"`, `"win32"` |
| `ci` | Whether running in CI | `true` |
| `tty` | Whether a terminal is attached to stdin, which usually means a person typed the command | `true` |
| `agent` | Name of the AI coding agent that ran the command, if any | `"claude"` |
| `mcpClient` | Name the MCP client reports when it connects (only for `mcp`) | `"claude-code"`, `"cursor-vscode"` |
| `plugins` | Plugin names and their options (only for `generate`) | `[{ "name": "@kubb/plugin-ts", "options": { "output": { "path": "types" } } }]` |
| `duration` | Command execution time in milliseconds | `1432` |
| `filesCreated` | Number of files generated (only for `generate`) | `47` |
| `status` | Whether the command succeeded or failed | `"success"` |
### Commands that send telemetry
| Command | Description |
| --------------- | ------------------------------------------------------------------- |
| `kubb generate` | Sent after code generation completes or fails |
| `kubb validate` | Sent after OpenAPI validation completes or fails |
| `kubb mcp` | Sent when an MCP client connects, or when the server fails to start |
## What is not collected
Kubb never sends:
- OpenAPI specification contents
- File paths or directory structures
- Secrets, API keys, or tokens
- Source code or generated code
- IP addresses or user identifiers
## How to opt out
Set `DO_NOT_TRACK` or `KUBB_DISABLE_TELEMETRY` to `1` or `true`:
```shell [Terminal]
DO_NOT_TRACK=1 kubb generate
```
`DO_NOT_TRACK` follows the [cross-tool convention](https://consoledonottrack.com/).
## Data transmission
Telemetry is formatted as [OpenTelemetry OTLP](https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/) traces. Kubb sends them to `https://otlp.kubb.dev/v1/traces` at the end of each command. The request fires only when you are online. It times out after 5 seconds and fails silently if anything goes wrong.
---
- **Page:** Diagnostics · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/diagnostics
- **Description:** Reference for Kubb's diagnostic codes, the stable codes Kubb prints when a build fails, with causes and fixes.
# Diagnostics
When a build fails, Kubb prints a diagnostic with a stable code, the message, the location in your
document, and a suggested fix. In a terminal, Kubb groups problems by plugin, with the code on the right and a link to its entry below:
```text [Terminal]
plugin-ts
✖ Could not find #/components/schemas/Owner KUBB_REF_NOT_FOUND
at #/components/schemas/Pet/properties/owner
fix Add the missing definition under components.schemas, or fix the $ref.
↳ Learn more kubb.dev/docs/5.x/reference/diagnostics#kubb-ref-not-found
```
When an AI coding agent, CI, or a pipe reads the output, Kubb prints plain labeled rows instead. The rows include the cause and fix from this page, so the output alone explains the problem. A crash adds `caused by:` and the first `stack:` frames:
```text [Agent]
error KUBB_REF_NOT_FOUND [plugin-ts]: Could not find #/components/schemas/Owner
at: #/components/schemas/Pet/properties/owner
why: A `$ref` could not be resolved in the source document.
fix: Add the missing definition under components.schemas, or fix the $ref.
docs: https://kubb.dev/docs/5.x/reference/diagnostics#kubb-ref-not-found
Kubb failed: 1 error (plugin-ts). Exit code 1.
Rerun with --reporter json for machine-readable diagnostics.
```
## Codes
Find the code printed by Kubb below. Each entry explains the cause and the fix.
## Errors
An error fails the run with a non-zero exit code.
### KUBB_ADAPTER_FAILED: Adapter failed {#kubb-adapter-failed}
The adapter threw an unexpected error while parsing the input. Errors the adapter reports on purpose, such as `KUBB_REF_NOT_FOUND`, keep their own code.
Check the input and the adapter options. If it is a bug, report it to the adapter's maintainers with the stack trace. Kubb prints the stack for this code, and `--reporter json` includes it as `stack`. When the adapter sets [`meta.issues`](/docs/5.x/reference/kit/extensions#meta), Kubb prints its issue tracker as a `report:` link.
### KUBB_ADAPTER_REQUIRED: Adapter required {#kubb-adapter-required}
An action needs an adapter but none is configured.
Set `adapter` in your config, for example `adapterOas()`. Standard `defineConfig` supplies the default OpenAPI adapter, so this catalog code is not currently emitted for an omitted adapter.
### KUBB_BARREL_DUPLICATE_EXPORT: Duplicate barrel export {#kubb-barrel-duplicate-export}
Two files in the same barrel directory export the same name. The barrel keeps the first export and drops the rest, so the generated code still parses, but the run is marked failed.
Rename the colliding declarations, change the resolver, or separate their output directories. A type and a value may share a name.
### KUBB_CLEAN_ROOT: Clean targets the project root {#kubb-clean-root}
`output.clean` removes generated code before a build. Kubb stops the build instead of wiping your project when `output.path` resolves to the project root or a parent of it, which would delete `kubb.config` and every source file.
Use a generated subdirectory such as `./src/gen`. Disable `output.clean` if it contains hand-written files. Kubb rejects cleaning the project root or a parent directory.
### KUBB_FORMAT_FAILED: Format failed {#kubb-format-failed}
The formatter pass over the generated files failed. Formatting runs after generation. The files are written, but the run is marked failed.
Check that the formatter is installed and its config is valid. Run it against the output directory to inspect the error, or change `output.format`.
### KUBB_INCOMPATIBLE_DEPENDENCY: Incompatible dependency {#kubb-incompatible-dependency}
A plugin's `dependencies` record sets a `version` range, and the configured plugin's `meta.version` falls outside it. Kubb skips the check when the dependency has no `meta.version`.
Install a version of the dependency inside the range, or a version of the dependent plugin that supports the installed dependency.
### KUBB_INCOMPATIBLE_EXTENSION: Incompatible extension {#kubb-incompatible-extension}
A plugin sets `meta.compatibility.kubb` or `meta.compatibility.node` to a range the running Kubb or Node.js version does not satisfy. Kubb checks this before any plugin runs.
Upgrade Kubb or Node.js to a version in the range, or install a version of the plugin that supports your current Kubb and Node.js.
### KUBB_INPUT_NOT_FOUND: Input not found {#kubb-input-not-found}
The file set as `input` (or passed as `kubb generate PATH`) could not be read. The OpenAPI adapter checks the path before parsing, so the run stops here instead of failing later with a vague read error.
Check that the file exists and is readable. Use a path relative to `kubb.config.ts`, an absolute path, or a full URL for a remote spec.
### KUBB_INPUT_REQUEST_FAILED: Input request failed {#kubb-input-request-failed}
A URL set as `input` answered with a 4xx or 5xx status instead of the OpenAPI document. The server was reached, so either the URL is wrong or the endpoint refused to serve the document.
Fetch the URL with `curl` and confirm it serves the OpenAPI document. For a protected document, download it and use the local file. Check server logs for a 5xx response. This also applies to remote `$ref` requests.
### KUBB_INPUT_REQUIRED: Input required {#kubb-input-required}
An adapter is configured but no `input` was provided, so there is nothing to parse.
Set `input` to a file path, URL, inline JSON/YAML spec, or parsed document. If merging documents, provide at least one input.
### KUBB_INPUT_UNREACHABLE: Input unreachable {#kubb-input-unreachable}
A URL set as `input` never answered, so the request failed before a status came back.
Start the server and check its host and port. Fetch the URL from the machine running Kubb. Connect to any required VPN or proxy, or use a downloaded spec. The message includes the connection failure reason.
### KUBB_INTERNAL_ERROR: Internal error {#kubb-internal-error}
Kubb hit a state it does not expect. This is a bug in Kubb, not in your config or your spec.
Rerun with `--reporter json` or `--verbose` to get the stack. Then [open an issue](https://github.com/kubb-labs/kubb/issues) with the spec and config that trigger it.
### KUBB_INVALID_DOCUMENT: Invalid document {#kubb-invalid-document}
The document resolved from `input` cannot be read as an OpenAPI or Swagger document. Its JSON or YAML has a syntax error, it declares neither `openapi` nor `swagger`, or its version cannot be upgraded to OpenAPI 3.1.
Fix the syntax at the line the message reports, and check that `input` points at the spec and not an HTML page. Use a Swagger 2.0, OpenAPI 3.0, or OpenAPI 3.1 document, and pass the document itself rather than a wrapper. Missing versions fail even when validation is disabled.
### KUBB_INVALID_PLUGIN_OPTIONS: Invalid plugin options {#kubb-invalid-plugin-options}
A plugin was given options that cannot be honored together. The main case is `output.mode` resolving to `'file'` while a `group` option is also set, or, for `@kubb/plugin-fetch`/`@kubb/plugin-axios`, while `sdk.mode: 'tag'` is set. Both pair a single-file output with an option that only makes sense split across several files, so the build stops instead of producing a layout the options do not describe.
Single-file output cannot use `group` or `sdk.mode: 'tag'`. Remove grouping, use `sdk.mode: 'flat'`, or write to a directory. A file extension in `output.path` implies file mode unless you explicitly select directory mode.
### KUBB_INVALID_SERVER_VARIABLE: Invalid server variable {#kubb-invalid-server-variable}
A server variable resolves to a value that its `enum` does not allow.
Choose a variable value allowed by its `enum`, correct the default, or update the enum to match the server.
### KUBB_LEGACY_INPUT: Legacy input shape {#kubb-legacy-input}
`input` is a `{ path }` or `{ data }` wrapper. v4 used it to point at a document, and v5 takes the value directly.
Replace `input: { path: './spec.yaml' }` with `input: './spec.yaml'`, or `input: { data: spec }` with `input: spec`.
### KUBB_LINT_FAILED: Lint failed {#kubb-lint-failed}
The linter pass over the generated files failed. Linting runs after generation. The files are written, but the run is marked failed.
Check that the linter is installed and configured. Run it manually against the output. Adjust rules for generated files or change `output.lint`.
### KUBB_MISSING_DEPENDENCY: Missing dependency {#kubb-missing-dependency}
A plugin lists another plugin in its `dependencies` record without `optional: true`, and the config does not include it. A `dependencies` array only orders plugins and never raises this code.
Install the missing plugin and add it to `plugins` in `kubb.config.ts`.
### KUBB_NO_CONTEXT: No plugin context {#kubb-no-context}
A `kubb/kit` composable such as `useKubb()` or `addGenerator()` ran outside `setup` and `kubb:plugin:setup`. Composables read the context of the plugin being set up, so outside setup there is no plugin to apply them to. The message names the composable that was called.
Call the composable inside `setup` or `kubb:plugin:setup`. Code that setup awaits also works, because the context survives an `await`. Generators and later hooks run after setup, so they cannot use composables.
### KUBB_PARSER_FAILED: Parser failed {#kubb-parser-failed}
A parser threw an unexpected error while printing a generated file.
Check the parser options. If it is a bug, report it to the parser's maintainers with the stack trace. Kubb prints the stack for this code, and `--reporter json` includes it as `stack`. When the parser sets [`meta.issues`](/docs/5.x/reference/kit/extensions#meta), Kubb prints its issue tracker as a `report:` link.
### KUBB_PATH_TRAVERSAL: Path traversal {#kubb-path-traversal}
A resolved output path escaped the output directory. Kubb refuses to write outside `output.path`, so a crafted spec or a misconfigured `group.name` cannot drop files anywhere on disk.
Keep generated paths within `output.path` and resolver `file.path` overrides within the project root. Reject `..` and path separators in names from the spec or `group.name`.
### KUBB_PLUGIN_FAILED: Plugin failed {#kubb-plugin-failed}
A plugin threw while generating, or reported an error through `ctx.error`. The diagnostic is attributed to the plugin and fails the run.
Check the plugin options and the node at the `at:` pointer. If it is a bug, report it to the plugin's maintainers with the stack trace. Kubb prints the stack for this code, and `--reporter json` includes it as `stack`. When the plugin sets [`meta.issues`](/docs/5.x/reference/kit/extensions#meta), Kubb prints its issue tracker as a `report:` link. Include a spec fragment that reproduces it. The diagnostic preserves an underlying error as its cause. For structured errors, plugin authors can use [`Diagnostics.Error` or `Diagnostics.report`](/docs/5.x/reference/kit/engine#diagnostics).
### KUBB_PLUGIN_NOT_FOUND: Plugin not found {#kubb-plugin-not-found}
A plugin requires another plugin that is not in the config.
Install the required plugin and add it to `plugins`, or remove its dependent plugin. Order does not matter. The adapter reads OpenAPI in v5, so do not add `@kubb/plugin-oas`.
### KUBB_POST_GENERATE_FAILED: Post-generate command failed {#kubb-post-generate-failed}
A post-generate command (`output.postGenerate`) exited with a non-zero status. These commands run after generation. The files are written, but the run is marked failed.
Run the command manually from the project root. Check the binary, spelling, and configuration. These commands run after formatting and linting.
### KUBB_REF_NOT_FOUND: Reference not found {#kubb-ref-not-found}
A `$ref` points at a definition that does not exist in the document.
Add the missing definition or correct the `$ref`. Run `kubb validate` before generation. Bundle documents with external references when needed.
### KUBB_UNKNOWN: Unknown error {#kubb-unknown}
A fallback for an error that does not yet carry a specific diagnostic code.
Run `kubb generate --reporter file` for a log under `.kubb/`, or use `--verbose`. Inspect the message and stack. Report unclear failures with the message and `Environment:` block. Unclassified errors have no suggested fix or docs URL in CLI output.
## Warnings
A warning is reported and the run continues.
### KUBB_INVALID_SPEC: Invalid spec {#kubb-invalid-spec}
The document does not pass OpenAPI schema validation. Kubb reports each problem and keeps generating, but the output can be incomplete or wrong. `@kubb/adapter-oas` checks this when [`validate`](/extensions/kubb-labs/adapter-oas/options#validate) is `true`, the default.
Fix the reported problem in the spec. Run [`kubb validate`](/docs/5.x/reference/commands/validate) to list every error with its location. Set `validate: false` on the adapter to skip the check.
### KUBB_PLUGIN_WARNING: Plugin warning {#kubb-plugin-warning}
A plugin reported a non-fatal warning through `ctx.warn`.
Read the message and adjust the input or plugin options as needed. Plugin authors can use `Diagnostics.report` for a stable code and source pointer.
### KUBB_UNSUPPORTED_FORMAT: Unsupported format {#kubb-unsupported-format}
A schema's `format` is not one Kubb maps to a specific type, so it falls back to the base type.
Use a supported format, omit it if the base type is sufficient, or map it through a custom parser or plugin.
## Info
An info diagnostic is advisory and never fails the run.
### KUBB_DEPRECATED: Deprecated {#kubb-deprecated}
A referenced schema or operation is marked `deprecated`.
Move away from the deprecated definition when possible. Generation continues unchanged, and the notice may recur on each run.
### KUBB_PERFORMANCE: Performance {#kubb-performance}
Records a plugin's elapsed time. Kubb collects one per plugin during a build.
This bookkeeping code is not printed as a terminal diagnostic. Run `kubb generate --verbose` to inspect plugin timings. The reported duration sums generation time and excludes config loading, formatting, linting, and post-generate hooks.
### KUBB_PLUGIN_INFO: Plugin info {#kubb-plugin-info}
A plugin reported an informational message through `ctx.info`.
No action is required. The plugin name and message appear in the summary and JSON report. Plugin authors can use `Diagnostics.report` for a stable code and source pointer.
### KUBB_UPDATE_AVAILABLE: Update available {#kubb-update-available}
A newer Kubb version is published on npm than the one running.
Update Kubb and your project plugins through your package manager.
## Machine-readable output
`kubb generate --reporter json` prints a stable report to stdout. The output is a JSON array with
one report per config, so a single-config run still prints `[ ... ]`. CI can read diagnostics
without scraping the terminal:
```json [Report]
[
{
"name": "",
"status": "failed",
"plugins": { "passed": 2, "failed": ["plugin-zod"], "total": 3 },
"counts": { "errors": 1, "warnings": 0, "infos": 0 },
"filesCreated": 0,
"durationMs": 312,
"output": "/project/src/gen",
"timings": [{ "plugin": "plugin-ts", "durationMs": 84 }],
"diagnostics": [
{
"code": "KUBB_REF_NOT_FOUND",
"severity": "error",
"message": "Could not find a definition for #/components/schemas/Pet.",
"title": "Reference not found",
"cause": "A `$ref` could not be resolved in the source document.",
"location": { "kind": "schema", "pointer": "#/components/schemas/Pet" },
"help": "Add the schema under components.schemas, or fix the $ref. Run `kubb validate` to check the spec.",
"docsUrl": "https://kubb.dev/docs/5.x/reference/diagnostics#kubb-ref-not-found"
}
]
}
]
```
Each config emits one report. `counts` totals the `problem` diagnostics by severity. `timings` lists
per-plugin durations slowest first. `name` is the config name, empty when unnamed.
Each diagnostic carries the catalog `title` and `cause` for its code, so an agent can act on it
without opening this page. `help` falls back to the catalog fix when the diagnostic has none.
When the diagnostic wraps a thrown error, `causes` lists the messages of the underlying errors,
and a crash (`KUBB_UNKNOWN` or a `*_FAILED` extension code) adds the root `stack`.
The exit code is unchanged: non-zero on any error. See [`--reporter`](/docs/5.x/reference/commands/generate#reporters)
for the other reporters.
---
- **Page:** Ecosystem · Kubb
- **Source:** https://kubb.dev/docs/5.x/resources/ecosystem
- **Description:** Discover projects built with Kubb, articles featuring Kubb, and community resources. See how developers use Kubb for OpenAPI code generation.
# Ecosystem
Projects and articles from the community.
## Production projects
::card-group
:::card{title="KOPER" to="https://github.com/dxloop/koper"}
A full-stack framework that uses Kubb for type-safe API integration.
:::
:::card{title="Xata MCP Server" to="https://xata.io/blog/built-xata-mcp-server"}
Built with Kubb's OpenAPI-to-MCP generation.
:::
:::card{title="ClickHouse with MooseStack" to="https://clickhouse.com/blog/clickhouse-powered-apis-in-react-app-moosestack#bridging-to-the-frontend"}
Powers React-app APIs with Kubb.
:::
:::card{title="Fiveonefour" to="https://docs.fiveonefour.com/moose/apis/openapi-sdk"}
Generates OpenAPI SDKs with Kubb.
:::
::
## Articles and tutorials
::card-group
:::card{title="API Consumption with OpenAPI and Typed Code" to="https://www.rocketseat.com.br/blog/artigos/post/consumo-apis-openapi-codigo-tipado"}
RocketSeat covers front-end API consumption with Kubb.
:::
:::card{title="OpenAPI to Frontend" to="https://apisyouwonthate.com/newsletter/openapi-to-frontend/"}
APIs You Won't Hate uses OpenAPI specs for frontend work.
:::
:::card{title="Securing Auth0 API Calls in Next.js" to="https://medium.com/@laxman.pokhrel.101/from-headache-to-harmony-securing-auth0-api-calls-in-next-js-54fc117bfb92"}
A Medium post that combines Kubb, Axios, and the Next.js App Router.
:::
::
## Listed in
- [TanStack Query Community Projects](https://tanstack.com/query/v5/docs/framework/react/community/community-projects)
- [Zod Ecosystem](https://zod.dev/ecosystem?id=x-to-zod) under "X to Zod" tools
## Community
Ask questions on [Discord](https://discord.gg/shfBFeczrm). Built something with Kubb? Share it on [GitHub Discussions](https://github.com/kubb-labs/kubb/discussions) and we will add it here.
---
- **Page:** kubb list · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/commands/list
- **Description:** The list command shows the installed Kubb extensions with their registry id, installed version, pinned registry version, and available updates.
# kubb list
Run `kubb list` to see the Kubb extensions installed in the current project, the version the [Kubb registry](/docs/5.x/reference/registry) pins for each, and whether an update exists. It takes no arguments or options.
## Usage
```shell [Terminal]
kubb list
```
```text [Output]
ID PACKAGE INSTALLED REGISTRY UPDATE
kubb-labs/plugin-ts @kubb/plugin-ts 5.4.2 5.4.4 yes
kubb-labs/plugin-zod @kubb/plugin-zod 5.4.4 5.4.4 no
- @acme/kubb-plugin-graphql 1.0.0 - no
```
## Columns
| Column | Description |
| ----------- | ----------- |
| `ID` | The registry id, or `-` when the registry does not list the package. |
| `PACKAGE` | The npm package name. |
| `INSTALLED` | The installed version, or `-` when the package is not installed. |
| `REGISTRY` | The version the registry pins, or `-` when the registry does not list the package. |
| `UPDATE` | `yes` when the installed version is older than the pinned one, or unknown. Run [`kubb update`](/docs/5.x/reference/commands/update) to install it. |
## Which packages it lists
`kubb list` shows each package in `dependencies` or `devDependencies` of the `package.json` in the current directory that ships a valid [`kubb-extension.json`](/docs/5.x/reference/kit/manifest) or is in the registry.
Extensions that ship inside `kubb`, such as `@kubb/adapter-oas` and `@kubb/plugin-barrel`, appear only when `package.json` lists them directly.
When the registry cannot be read, the CLI prints `Showing installed extensions only: ` and lists the packages that ship a manifest. When it finds nothing, it prints `No installed extensions found.`
## Environment variables
| Variable | Default | Description |
| --------------- | --------------------------- | ----------- |
| `KUBB_REGISTRY` | `https://kubb.dev/registry` | Base URL of the registry to read. See [Host your own registry](/docs/5.x/reference/registry#host-your-own-registry). |
## Exit codes
`kubb list` exits with code 1 when `KUBB_REGISTRY` is not an `http://` or `https://` URL. A registry that cannot be reached does not fail the command.
---
- **Page:** kubb update · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/commands/update
- **Description:** The update command moves installed Kubb extensions to the version the Kubb extension registry pins, or lists the available updates with --check.
# kubb update
Run `kubb update` to move installed extensions to the version the [Kubb registry](/docs/5.x/reference/registry) pins. It lists the updates with the kind and the version change of each extension, asks which ones to install, and installs them with your project's package manager. With `--yes`, it installs all of them. It does not change `kubb.config.ts`.
## Usage
Update every installed extension the registry lists:
```shell [Terminal]
kubb update
```
```text [Output]
@kubb/plugin-ts plugin 5.0.0 -> 5.2.0
@kubb/plugin-zod plugin 5.1.0 -> 5.2.0
│
◆ Select the updates to install:
│ ◼ @kubb/plugin-ts (plugin 5.0.0 -> 5.2.0)
│ ◼ @kubb/plugin-zod (plugin 5.1.0 -> 5.2.0)
│ ↑/↓ to navigate • Space: select • Enter: confirm
```
Every update starts selected. Press Space to leave one out, and Enter to install the rest.
List the updates without installing them:
```shell [Terminal]
kubb update --check
```
Install the updates for two extensions without the prompt:
```shell [Terminal]
kubb update plugin-zod plugin-ts --yes
```
## Arguments
| Argument | Required | Description |
| ---------- | -------- | ----------- |
| `[ids...]` | `false` | Registry ids to update, as `/` or a bare `` for `kubb-labs/`. Without ids, every installed extension the registry lists is checked. |
## Options
| Option | Default | Description |
| ------------- | ------- | ----------- |
| `--check` | `false` | List the available updates without installing them. |
| `--yes`, `-y` | `false` | Install every update without asking. |
## Which extensions it updates
`kubb update` checks the registry extensions listed in `dependencies` or `devDependencies` of the `package.json` in the current directory. An extension gets an update when its installed version is older than the pinned one, or when it is not installed. A version newer than the pin is left alone, so `kubb update` never downgrades.
An update that does not support your Kubb or Node.js version is skipped with `Skipped : `. An extension pinned to a GitHub release installs as `github:/#`.
An id that matches no installed extension prints ` is not installed, or not in the registry.` and the other ids still update. When nothing is outdated, the CLI prints `Every installed extension is up to date.`
## Environment variables
| Variable | Default | Description |
| --------------- | --------------------------- | ----------- |
| `KUBB_REGISTRY` | `https://kubb.dev/registry` | Base URL of the registry to read. See [Host your own registry](/docs/5.x/reference/registry#host-your-own-registry). |
## Exit codes
`kubb update` exits with code 1 when an id is invalid, the registry index cannot be read or is invalid, or the install fails. It exits with code 0 when there is nothing to update, with `--check`, and when you cancel at the prompt.
---
- **Page:** kubb mcp · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/commands/mcp
- **Description:** The mcp command starts a Model Context Protocol server so AI clients can validate your spec, scaffold a config, and run generation.
# kubb mcp
Run `kubb mcp` to start a [Model Context Protocol](https://modelcontextprotocol.io/) server. AI clients such as Claude Code, Claude Desktop, Cursor, and VS Code can then validate your spec, scaffold a `kubb.config.ts`, and run generation.
> [!WARNING]
> This feature is under active development. Use it with caution and expect breaking changes.
::terminal
---
command: kubb mcp
output:
- ⏳ Starting MCP server...
- This feature is still under development, use with caution
---
::
The server uses the stdio transport, so the client starts it as a local process. [Set up the MCP server](/docs/5.x/ai/mcp) shows the client configuration.
## Tools
| Tool | Parameters | Description |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `generate` | `config?` (path to a config file inside the working directory. When omitted, the server searches the same way `kubb generate` does: `.kubbrc` then `kubb.config` with the `ts`, `mts`, `cts`, `js`, `mjs`, `cjs` extensions, in the working directory, its `.config/` and `configs/` folders, then each parent folder), `input?` (spec path, overrides the config), `output?` (output directory, overrides the config), `logLevel?` (`silent`, `info`, `verbose`, default `info`, passed to a config that exports a function) | Runs the Kubb pipeline. On success, it returns the file count and the warnings and diagnostics raised. On failure, it returns each diagnostic with its code, fix, and docs link instead. A config that exports an array runs its first entry. |
| `validate` | `input` (path or URL, required) | Validates an OpenAPI or Swagger document with the bundled OpenAPI adapter. |
| `init` | `input?` (default `./openapi.yaml`), `output?` (default `./src/gen`) | Writes a `kubb.config.ts` with an empty `plugins` array in the working directory without prompts. It does not install packages or add plugins: its reply tells the agent to run `kubb add --yes` for each one. It fails when `kubb.config.ts` already exists. |
## Working directory
The server runs in the folder the client starts it in. `generate` looks for its config there, then in its parent folders, and rejects a `config` path outside it, and `init` writes `kubb.config.ts` there. [Set up the MCP server](/docs/5.x/ai/mcp#working-directory) shows how to start the server in your project.
---
- **Page:** kubb generate · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/commands/generate
- **Description:** The generate command runs the Kubb code-generation pipeline based on your kubb.config.ts.
# kubb generate
Run `kubb generate` to read your [`kubb.config.ts`](/docs/5.x/reference/configuration) and run the code-generation pipeline. It's the default command, so running `kubb` with no arguments does the same.
## Usage
Generate from the input set in your config:
```shell [Terminal]
kubb generate
```
Pass an input file to override the config:
```shell [Terminal]
kubb generate ./petStore.yaml
```
## Arguments
| Argument | Description |
| --------- | -------------------------------------------------------------------------------------------- |
| `[input]` | Optional path or URL to a Swagger/OpenAPI document. Overrides the `input` set in the config. |
## Options
| Option | Default | Description |
| -------------------------------------------- | ------- | ------------------------------------------------------------------------- |
| `--config=`, `-c ` | | Path to a config file, such as `./kubb.staging.ts`. |
| `--log-level=`, `-l` | `info` | Set the verbosity. Use `verbose` to see plugin timings. |
| `--silent`, `-s` | `false` | Force the log level to `silent`. Suppresses output. |
| `--verbose` | `false` | Force the log level to `verbose`. Shows slow plugins. |
| `--reporter=` | | Pick which reporters to trigger, comma-separated. Defaults to `cli`. |
| `--watch`, `-w` | `false` | Re-run the pipeline whenever the input spec changes. |
| `--dry-run` | `false` | Preview a run without writing files, formatting, linting, or running post-generate commands. |
`--reporter` takes no short flag. The camelCase spellings from v4 (`--logLevel`, `--dryRun`) still work and print a deprecation warning.
## Reporters
A reporter decides how a run is rendered. The config registers available reporters with [`reporters`](/docs/5.x/reference/configuration). `--reporter` picks which ones to trigger by name, comma-separated (`--reporter cli,file`). Four reporters are registered by default.
| Reporter | Output |
| -------- | ------------------------------------------------------------------------------- |
| `cli` | The end-of-run summary in the terminal. Default. Uses plain text in non-interactive terminals and AI agent sessions. |
| `json` | A machine-readable report on stdout for CI. See [Diagnostics](/docs/5.x/reference/diagnostics#machine-readable-output) for the full JSON shape. |
| `file` | The run's diagnostics, written to `.kubb/kubb[-]-.log`. The `` segment is dropped when the config has no `name`. A run without diagnostics writes no file. |
| `html` | A browsable report directory with generated files and diagnostics, written to `.kubb/kubb[-]-/index.html`. |
Write a log file:
```shell [Terminal]
kubb generate --reporter file
```
Print a JSON report for CI. The exit code is non-zero on any error:
```shell [Terminal]
kubb generate --reporter json
```
---
- **Page:** kubb init · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/commands/init
- **Description:** The init command bootstraps a fresh Kubb project with an interactive wizard.
# kubb init
Run `kubb init` for an interactive setup wizard. Answer a few questions and Kubb creates a `package.json` if one is missing, installs your chosen plugins, and writes a ready-to-use `kubb.config.ts`.
## Usage
Run the command in the directory where your Kubb project lives:
```shell [Terminal]
npx kubb init
```
The wizard prompts for three things:
- The path to your OpenAPI/Swagger spec, a local file or a URL.
- The output directory for generated files.
- Which [plugins](/extensions/kind/plugins) to install, such as clients, hooks, validators, and mocks. The list comes from the [Kubb registry](/docs/5.x/reference/registry).
Kubb detects the package manager (`bun`, `pnpm`, `npm`, or `yarn`) from your project. It installs `kubb` at the exact version of the CLI you ran. Each plugin is added the way [`kubb add`](/docs/5.x/reference/commands/add) adds it: at the version the registry pins, and only when it supports the running Kubb and Node.js versions.
Before it installs anything, Kubb checks the [manifest](/docs/5.x/reference/kit/manifest) of each chosen plugin. If a plugin's `dependencies` are not all chosen, or a plugin with `role: "consumer"` (such as `plugin-react-query`) has no client plugin next to it, `kubb init` names what is missing and stops.
## Options
| Option | Default | Description |
| ---------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--yes`, `-y` | `false` | Skip all prompts and use the default values. |
| `--input`, `-i` | | Path to the OpenAPI specification (local file or URL). Bypasses the spec path prompt. |
| `--output`, `-o` | | Output directory for generated files. Bypasses the output directory prompt. |
| `--plugins` | | Comma-separated registry ids of the plugins to add, the same ids [`kubb add`](/docs/5.x/reference/commands/add) takes, such as `plugin-ts,plugin-zod`. Bypasses the plugin selection prompt. An id that is not in the registry stops `kubb init`. |
| `--dry-run` | `false` | Preview the wizard without installing packages or writing `kubb.config.ts`. |
Each flag skips only its own prompt and combines with `--yes`. Pass all three value flags and the wizard runs without prompts, no `--yes` needed.
## Examples
Run with the defaults and no prompts:
```shell [Terminal]
npx kubb init --yes
```
Run with no prompts and a specific spec, output directory, and plugins:
```shell [Terminal]
npx kubb init --input ./openapi.yaml --output ./src/gen --plugins plugin-ts,plugin-zod
```
Add `--dry-run` to preview what the wizard would install and write.
---
- **Page:** kubb studio · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/commands/studio
- **Description:** Command reference for connecting a project to Kubb Studio, managing pairing and permissions, and publishing CI snapshots.
# kubb studio
Run `kubb studio` to connect a project to [Kubb Studio](https://kubb.studio). The CLI runs generation on your machine and sends progress and generated file paths to Studio. Grant `--allow-read` to view generated file contents and diffs in the browser, and `--allow-read-ast` to share the parsed spec.
## Usage
Connect the current project. On the first run, approve the pairing code in Studio. The CLI then asks which permissions to grant for this project.
```shell [Terminal]
kubb studio
```
## Actions
The positional argument selects the action. It defaults to `connect`.
| Action | Description |
| ---------- | ----------------------------------------------------------------------- |
| `connect` | Hold a foreground session open and generate on request. |
| `start` | Resolve pairing and permissions, then connect this project in the background. |
| `stop` | Stop the background worker and keep its pairing. |
| `login` | Pair this machine again without opening a generation session. Saved permissions reset. |
| `logout` | Stop the background worker and forget this project's stored token. |
| `status` | Show worker state, log path, pairing, and saved permissions. |
| `snapshot` | Generate and pack a snapshot on this machine, upload it in one request, then exit. See [Publish snapshots from CI](/docs/5.x/integrations/ci). |
## Background connection
Run `start`, `status`, and `stop` from the same project directory. `start` resolves pairing and permission prompts before detaching, then returns while the worker connects.
`status` reports `starting`, `connected`, `reconnecting`, `authentication required`, or `stopped`. Only one worker can own a project. Stop it before using foreground `connect`.
The worker survives terminal closure and retries temporary connection failures. Restart it after a crash or reboot. If its token is rejected, run `kubb studio login`, then `kubb studio start`. To change its URL or config, stop it and start it with the new flags. Flags can only add permissions. `login` resets the saved ones.
The CLI keeps credentials, worker state, and the worker log in `KUBB_HOME`, which defaults to `~/.kubb`. `status` prints the log path. `stop` waits for a running generation to clean up, and `logout` stops the worker before it removes credentials. An interrupted job does not run again.
## Options
| Option | Default | Description |
| ------------------------------------------ | --------------------- | ---------------------------------------------------------------------------------- |
| `--config=`, `-c ` | | Path to a config file, such as `./kubb.staging.ts`. |
| `--url=` | `https://kubb.studio` | URL for Kubb Studio. Plain `http://` works only for `localhost`, `127.0.0.1`, or `[::1]`. |
| `--allow-read` | `false` | Let Studio read generated file contents. Asked once per project when omitted. |
| `--allow-read-ast` | `false` | Let Studio read the parsed spec (the Kubb AST). Asked once per project when omitted. |
| `--allow-write` | `false` | Write generated files to disk. Asked once per project when omitted. |
| `--allow-config-edit` | `false` | Let Studio change plugin options in `kubb.config.ts`. Asked once per project. |
| `--allow-exec` | `false` | Run the formatter, the linter, and `output.postGenerate`. Asked once per project. |
| `--no-open` | | Do not open the approval page in a browser. |
| `--log-level=`, `-l`| `info` | Set the verbosity. |
| `--token=` | | `snapshot` only: organization CI API key. Defaults to `KUBB_TOKEN`. |
| `--id=` | | `snapshot` only: stable identity for the CI agent. Auto-detected on GitHub Actions, GitLab CI, Bitbucket Pipelines and CircleCI. |
| `--base-id=` | | `snapshot` only: the `--id` of another CI agent, such as the base branch's, to also compare with. Auto-detected on GitHub pull requests and GitLab merge requests. |
| `--name=` | | `snapshot` only: package name for the tarball. Defaults to the name in the nearest `package.json` that has a name and a version. |
| `--package-version=` | | `snapshot` only: package version for the tarball. Defaults to the version in the nearest `package.json` that has a name and a version. |
| `--json` | `false` | `snapshot` only: print the result as one JSON object instead of a summary. |
`snapshot` takes no `--allow-*` flag. It generates like `kubb generate`: it writes to `output.path`, then runs the formatter, the linter, and `output.postGenerate`. It refuses a tarball over 50 MB.
Without `--allow-read`, a session still generates and reports file paths, but Studio cannot display their contents. The CLI asks about permissions not supplied as flags and remembers answers per project directory. Without a TTY it skips the permission prompts, so pass the flags the run needs. In CI it also refuses to pair and needs stored credentials, so use `snapshot` there instead.
Each action exits with code 1 when it fails.
## Environment variables
| Variable | Description |
| ------------------ | ---------------------------------------------------------------------------------- |
| `KUBB_HOME` | Directory the CLI keeps its Studio state in. Defaults to `~/.kubb`. |
| `KUBB_TOKEN` | `snapshot` only: organization CI API key. Same as `--token`. |
| `KUBB_AGENT_MAX_GENERATIONS` | How many recent generations the agent keeps for Studio to read. Defaults to `8`. |
| `KUBB_AGENT_MAX_GENERATIONS_MB` | Size cap in MB for the kept generations. Defaults to `100`. |
| `KUBB_AGENT_MAX_SNAPSHOT_MB` | Size cap in MB for the on-disk copy kept for diffs. Defaults to `50`. |
## Snapshot output
`--json` prints one JSON object with `id`, `name`, `version`, `integrity`, `url`, `snapshotIdUrl`, `expiresAt`, and `agentUrl`. It also includes `changes` and `branchChanges` when comparisons are available. Installing a snapshot requires a separate `registry` API key.
| JSON field | Compared with |
| --- | --- |
| `changes` | The previous snapshot on the same pull request or branch. |
| `branchChanges` | The latest snapshot of the agent named by `--base-id`, or of the base branch detected on a GitHub pull request or GitLab merge request. Its `branch` field names that agent. Its `baseFound` field distinguishes a branch with no CI agent from one with an agent that has no snapshot of this package yet. |
## CI agent identity
`snapshot` detects GitHub Actions, GitLab CI, Bitbucket Pipelines, and CircleCI. Other providers require a stable `--id`. Use a stable `--id` on the base branch and pass that identity as `--base-id` on pull request runs. Passing `--id` turns off base detection, so also pass `--base-id` to get `branchChanges`.
### GitLab CI
Every pipeline on a merge request publishes to one CI agent. A branch pipeline publishes to one agent per branch, so the default branch has one agent too. Pass `--id` to group runs your own way.
A merge request pipeline compares with its target branch. The snapshot reports which generated files changed against that branch's latest snapshot in `branchChanges`, and against the merge request's previous pipeline in `changes`. The commit it records is the head of the source branch.
## Plugins in Studio {#plugins-in-studio}
Studio builds its plugin list and option forms from [extension manifests](/docs/5.x/reference/kit/manifest). When Studio connects, the agent reports each extension that is installed in the project, ships a valid `kubb-extension.json`, and comes from one of these places:
- The `dependencies` and `devDependencies` in the project's `package.json`.
- The packages `kubb.config.ts` imports.
- The extensions that ship with `kubb`: `@kubb/adapter-oas`, `@kubb/parser-ts`, `@kubb/parser-md`, and `@kubb/plugin-barrel`.
A third-party plugin works in Studio once it is installed in the project and ships a manifest with `kind: "plugin"`. It needs no registry entry. Install it with [`kubb add`](/docs/5.x/reference/commands/add) or your package manager, then reconnect so Studio sees it.
The adapter and the parsers the config registers get a settings form the same way, from the `options` in their manifest. The agent reports them on connect with a JSON copy of their options, and the edits Studio sends on generate are merged over the options in `kubb.config.ts`. A `null` value unsets an option for that run, so the extension's default applies. An extension without a manifest, such as `parserTsx`, is listed without fields.
The agent imports a plugin package only when it is a `@kubb/plugin-*` package, or an installed package whose manifest has `kind: "plugin"`. It calls the factory the manifest names in `export`. The agent refuses any other package name before it imports anything, and config edits follow the same rule.
| Agent | Plugins it can run |
| --- | --- |
| `kubb studio` on your machine | `@kubb/plugin-*` packages and plugins installed in the project that ship a manifest. |
| Docker agent and hosted sandbox | Only the packages installed in their image. They install nothing at runtime. |
Studio also lists plugins from the [kubb.dev registry](/docs/5.x/reference/registry). A plugin that the agent cannot run shows as not installed, with a `kubb add ` hint to install it.
---
- **Page:** AST and node builders · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/kit/ast
- **Description:** The ast namespace groups the factory node builders, the transform and collect visitors, the guards, the ref and naming helpers, the macro engine, and the printer helper behind one import.
# AST and node builders
## `ast`
`ast` is `kubb/kit`'s namespace for the entire AST surface, the same way TypeScript groups its node constructors under `ts.factory`. It carries the `factory` node builders, the `transform` and `collect` visitors, the guards, the ref and string helpers, and the macro engine.
```typescript twoslash [ast-namespace.ts]
import { ast } from 'kubb/kit'
const root = ast.factory.createInput({
schemas: [ast.factory.createSchema({ name: 'Pet', type: 'object', properties: [] })],
operations: [],
})
```
Node building goes through `ast.factory`. `ast.factory.createFile`, `ast.factory.createSource`, and `ast.factory.createText` build the `FileNode` tree a generator returns. See the [factory table](#factory-functions) below.
For why the AST exists and how it fits the pipeline, see [AST concepts](/docs/5.x/explanation/architecture#ast).
## Schema node types
A `SchemaNode` is discriminated by its `type`. The values fall into three families.
### Structural types
| Type | Description | TypeScript |
| -------------- | --------------------------------------- | ------------------------------- |
| `object` | Object with named properties | `{ name: string; age: number }` |
| `array` | Sequence of items | `string[]` |
| `tuple` | Fixed-length array with typed positions | `[string, number, boolean]` |
| `union` | One of multiple types | `string \| number` |
| `intersection` | Combination of multiple types | `A & B` |
| `enum` | Fixed set of literal values | `'active' \| 'inactive'` |
### Scalar types
| Type | Description | TypeScript |
| --------- | -------------- | ---------- |
| `string` | Text value | `string` |
| `number` | Numeric value | `number` |
| `integer` | Whole number | `number` |
| `bigint` | Large integer | `bigint` |
| `boolean` | True/false | `boolean` |
| `null` | Null value | `null` |
| `any` | Any value | `any` |
| `unknown` | Unknown value | `unknown` |
| `void` | No value | `void` |
| `never` | Never produced | `never` |
### Special types
| Type | Description | Example |
| ---------- | --------------------------- | -------------------------------------- |
| `ref` | Reference to another schema | `Pet` (from `$ref`) |
| `date` | ISO date | `2024-01-15` |
| `datetime` | ISO datetime | `2024-01-15T10:30:00Z` |
| `time` | ISO time | `10:30:00` |
| `uuid` | UUID string | `550e8400-e29b-41d4-a716-446655440000` |
| `email` | Email address | `user@example.com` |
| `url` | URL string | `https://example.com` |
| `blob` | Binary data | Raw bytes |
## Factory functions {#factory-functions}
Factories return defaulted, fully typed nodes for adapters and generator handlers. Never build AST literals by hand. Besides `createInput`, `createSchema`, and `createOperation`, the namespace provides constructors for source files and the TypeScript-level artifacts generators emit:
| Factory | Purpose |
| ------------------------------------------------------------------- | -------------------------------------------------------- |
| `createFile`, `createSource`, `createText` | Build `FileNode`s emitted by generators. |
| `createImport`, `createExport` | Emit `import` / `export` statements. |
| `createConst`, `createFunction`, `createArrowFunction`, `createJsx` | Emit TypeScript declarations and JSX. |
| `createParameter` | Describe operation parameters. |
| `createProperty`, `createType` | Compose object properties and TypeScript types. |
| `createResponse`, `createRequestBody`, `createContent` | Model responses, request bodies, and content entries. |
| `createBreak` | Emit line breaks between nodes. |
## Visitors {#visitors}
Two visitor functions cover the common traversal patterns: `transform` rewrites the tree and `collect` gathers nodes. Visitor objects use lowercase, kind-style keys (`input`, `operation`, `schema`, `property`, `parameter`, `response`). To rewrite nodes inside a plugin, reach for [macros](/docs/5.x/how-to/macros), which add names, ordering, and composition on top of `transform`. For logging, validation, or statistics, `collect` the nodes you care about.
### `transform`: synchronous, returns a new tree
```typescript twoslash [transform.ts]
import { ast } from 'kubb/kit'
const root = ast.factory.createInput({ schemas: [], operations: [] })
const enhanced = ast.transform(root, {
schema(node) {
if (node.type === 'object' && node.additionalProperties === undefined) {
return { ...node, additionalProperties: false }
}
return node
},
operation(node) {
return { ...node, tags: node.tags?.length ? node.tags : ['untagged'] }
},
})
```
Use `transform` to change AST structure, normalize inconsistencies, or annotate nodes.
### `collect`: gather matching nodes
`collect` is a generator function, so it yields matches lazily and you consume it with `for...of` or spread it into an array. When you want the array up front, call `collectSync`, which is the eager counterpart and returns `Array`.
```typescript twoslash [collect.ts]
import { ast } from 'kubb/kit'
const root = ast.factory.createInput({ schemas: [], operations: [] })
const mutations = ast.collectSync(root, {
operation(node) {
return node.method === 'POST' ? node : undefined
},
})
const deprecated = ast.collectSync(root, {
schema(node) {
return 'deprecated' in node && node.deprecated ? node : undefined
},
})
console.log(`POST operations: ${mutations.length}`)
console.log(`Deprecated schemas: ${deprecated.length}`)
```
Use `collect` to stream matches as you find them, and `collectSync` to find specific nodes, filter by a criterion, or build a list for later processing.
## Guards and narrowing {#guards-and-narrowing}
Kubb exports type guards and a `narrowSchema` helper for safe discrimination:
```typescript twoslash [guards.ts]
import { ast } from 'kubb/kit'
const root = ast.factory.createInput({ schemas: [], operations: [] })
for (const node of ast.collect(root, { schema: (node) => node })) {
const obj = ast.narrowSchema(node, 'object')
if (obj) {
console.log(`object with ${obj.properties.length} properties`)
}
if (node.type === 'ref') {
console.log(`reference to: ${node.ref}`)
}
}
for (const node of ast.collect(root, { operation: (node) => node })) {
if (ast.isHttpOperationNode(node)) {
console.log(`${node.method} ${node.path}`)
}
}
```
## Refs and naming helpers
The helpers split across two surfaces. `resolveRefName` ships on the `ast` namespace, like the guards and node types. `extractRefName`, `childName`, `enumPropName`, and `syncSchemaRef` are named exports of `kubb/kit` itself. The same split applies to `containsCircularRef` and the built-in macros below.
| Helper | Purpose |
| ---------------- | ------------------------------------------------------------------- |
| `extractRefName` | Turn `'#/components/schemas/Pet'` into `'Pet'`. |
| `resolveRefName` | Resolve the name a ref node emits, preferring its `targetName`. |
| `childName` | Derive a child property name from context. |
| `enumPropName` | Convert an enum value into a valid property name. |
| `syncSchemaRef` | Merge a ref node with its resolved schema, letting usage-site fields (`description`, `nullable`) override. |
```typescript twoslash [refs.ts]
import { extractRefName } from 'kubb/kit'
const name = extractRefName('#/components/schemas/Pet')
// ^?
```
## Schema graph
Analyze how schemas reference each other, to prune unused schemas or wrap circular ones in a lazy construct. `collectUsedSchemaNames` and `findCircularSchemas` ship on the `ast` namespace.
| Helper | Purpose |
| ------------------------ | ------------------------------------------------------------------------------------------------- |
| `collectUsedSchemaNames` | Collect the names of every top-level schema transitively used by a set of operations. Pair it with `include` filters to leave unreferenced schemas ungenerated. |
| `findCircularSchemas` | Find every schema that takes part in a circular dependency chain, so those positions can be wrapped in a lazy getter or `z.lazy(() => …)`. |
| `containsCircularRef` | Report whether a schema, or anything nested inside it, references a circular schema. |
## Constants
| Export | Purpose |
| ------------- | ------------------------------------------ |
| `schemaTypes` | Map of every schema `type` discriminant. |
## Macros
A macro is a named, composable transform built on `transform` that rewrites nodes before printing, adding ordering, gating, and reuse a bare visitor doesn't give you. See [Macros concepts](/docs/5.x/how-to/macros).
| Export | Purpose |
| --------------- | ------------------------------------------------ |
| `defineMacro` | Type a macro and read it as one definition. |
| `composeMacros` | Fold an ordered list of macros into one visitor. |
| `applyMacros` | Run a list of macros over a node tree. |
Kubb also ships built-in macros for common schema normalizations that any adapter can compose with its own. `macroDiscriminatorEnum`, `macroEnumName`, and `macroRenameSchema` read options, so call them to build the macro. Plugins that import another plugin's output compute names from the nodes they see, so register a rename on every plugin that touches the schema, for example by passing one shared `macros` array to each plugin.
| Macro | Purpose |
| ------------------------ | ------------------------------------------------------------------------------------------- |
| `macroSimplifyUnion` | Drop union members a broader scalar primitive already covers, such as a multi-value string enum next to `string`. |
| `macroDiscriminatorEnum` | Replace a discriminator property's schema with a string enum of its allowed values. |
| `macroEnumName` | Name an inline enum schema from its parent and property name. |
| `macroRenameSchema` | Rename a schema's declaration and stamp `targetName` on every ref pointing at it, so `resolver.imports` emits the new name everywhere. |
### Macro options and callbacks
A macro carries the per-kind callbacks of a [visitor](/docs/5.x/reference/kit/ast#visitors), plus a `name`, an optional `enforce` order, and an optional `match` predicate.
```typescript [Type definition]
type Macro = {
name: string
enforce?: 'pre' | 'post'
match?: (node: Node) => boolean
schema?(node: SchemaNode, context): SchemaNode | null | undefined
operation?(node: OperationNode, context): OperationNode | null | undefined
// input, output, property, parameter, response
}
```
Each callback returns a replacement node, or `undefined` or `null` to leave the node untouched.
## Printers
Lower-level helpers for parsers that turn the AST into source code:
| Export | Purpose |
| --------------- | -------------------------------------- |
| `createPrinter` | Typed helper for creating a `Printer`. |
`createPrinter` takes an `overrides` map to replace the handler for individual schema node types. Pass overrides through the `overrides` field rather than spreading them into `nodes`, otherwise `this.base` cannot find the original handler. The `printer.nodes` option on `@kubb/plugin-ts`, `@kubb/plugin-zod`, and `@kubb/plugin-faker` feeds this map. See [Customize printers](/docs/5.x/how-to/printers).
See [Import a custom codec](/extensions/kubb-labs/plugin-zod/guides/customization#import-a-custom-codec) for a complete example and [Parsers concepts](/docs/5.x/explanation/architecture#parsers) for how parsers consume printers.
### Printer handlers and context
The map is keyed by the schema `type` discriminant, such as `'string'`, `'integer'`, `'date'`, `'enum'`, or `'object'`. Supply only the handlers you want to replace and the built-in ones fill in the rest.
```typescript [Type definition]
type PrinterNodes = Partial<{
[K in SchemaType]: (this: Context, node: SchemaNodeByType[K]) => Output | null
}>
```
Handlers run with a `this` context, so write them as regular functions rather than arrow functions. `this.transform(node)` recurses into a nested schema node through the full handler map, overrides included. `this.base(node)` runs the built-in handler your override replaced, so you can wrap its output instead of rebuilding it. `this.options` reads the resolved printer options, such as `arrayType` on `@kubb/plugin-ts` or `direction` on `@kubb/plugin-zod`. Inside a handler, `this.import(ast.factory.createImport(...))` declares an import the printed code needs. The built-in generators collect these imports. In your own generator, call `printer.drainImports()` after printing to collect them.
---
- **Page:** Shared plugin options · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/plugin-options
- **Description:** The output, group, include, exclude, override, resolver and macros options that every Kubb generator plugin accepts, with their types, defaults and behavior.
# Shared plugin options
Every generator plugin accepts the options on this page. A plugin's own options page lists only the default it gives each one and links here for the behavior.
`@kubb/plugin-barrel` is the exception: it takes no arguments and is configured through [`output.barrel`](#output-barrel). `@kubb/plugin-redoc` accepts only `output.path`.
## output {#output}
Where the plugin writes its files and how they are exported.
| | |
| --- | --- |
| Type | `Output` |
| Required | `false` |
| Default | Set by each plugin, for example `{ path: 'types', barrel: { type: 'named' } }` for `@kubb/plugin-ts` |
An `output` you pass replaces the plugin default as a whole. Repeat `barrel` when you set `output` yourself, or the plugin falls back to `config.output.barrel`.
```typescript [kubb.config.ts]
import { pluginTs } from '@kubb/plugin-ts'
pluginTs({
output: {
path: 'models',
barrel: { type: 'named' },
banner: '/* eslint-disable */',
},
})
```
### output.path {#output-path}
Folder where the plugin writes its files, resolved against the global `output.path` on `defineConfig`. For a single file, give `path` a name with its extension, such as `'types.ts'`.
| | |
| --- | --- |
| Type | `string` |
| Required | `true` when `output` is set |
| Default | Set by each plugin |
### output.mode {#output-mode}
How generated code is consolidated into files.
| | |
| --- | --- |
| Type | `'directory' \| 'file'` |
| Required | `false` |
| Default | `'file'` when `output.path` has an extension, `'directory'` otherwise |
::field-group
:::field{name="'directory'"}
Writes one file per operation or schema under `output.path`. Use `group` to split those files into subfolders.
:::
:::field{name="'file'"}
Writes everything into a single file. `output.path` must include the file extension, such as `'types.ts'`.
:::
::
Leave `mode` unset and Kubb reads it from `output.path`. Set `mode: 'directory'` only to override that inference, for example for a directory name that carries a dot such as `'clients.v2'`.
> [!IMPORTANT]
> `group` needs directory output. Combining `group` with `mode: 'file'` stops the build with [`KUBB_INVALID_PLUGIN_OPTIONS`](/docs/5.x/reference/diagnostics#kubb-invalid-plugin-options).
### output.barrel {#output-barrel}
Controls how generated `index.ts` files re-export the plugin's output. Toggle the export style and depth to see the generated barrels.
::barrel-tree
::
| | |
| --- | --- |
| Type | `{ type: 'all' \| 'named', nested?: boolean } \| false` |
| Required | `false` |
| Default | `{ type: 'named' }` from the plugin's default `output`, `false` once you pass your own `output` without `barrel` |
::field-group
:::field{name="'named'"}
Re-exports each symbol by name. Use `{ type: 'named' }` for explicit imports and tree-shaking.
:::
:::field{name="'all'"}
Re-exports every symbol with `export *`. Use `{ type: 'all' }` for wildcard exports.
:::
:::field{name="false"}
Skips barrel generation for this plugin and drops its files from the root barrel.
:::
::
Add `nested: true`, for example `{ type: 'named', nested: true }`, to write an `index.ts` in every subdirectory that re-exports only what sits directly inside it. The root `output.barrel` on `defineConfig` has no `nested` field.
Kubb reads the plugin's own `output.barrel` first, falls back to `config.output.barrel` on `defineConfig`, and finally to `false`. See [`@kubb/plugin-barrel` options](/extensions/kubb-labs/plugin-barrel/options) for the `type` and `nested` fields in detail.
```typescript [kubb.config.ts]
import { pluginZod } from '@kubb/plugin-zod'
pluginZod({ output: { path: 'zod', barrel: { type: 'all', nested: true } } })
```
### output.banner {#output-banner}
Text added to the top of every generated file, such as a license header or a `@ts-nocheck` directive.
| | |
| --- | --- |
| Type | `string \| ((meta: BannerMeta) => string)` |
| Required | `false` |
A string is applied to every file, barrels included. A function receives the document info (`title`, `description`, `version`, `baseURL`) and per-file context (`filePath`, `baseName`, `isBarrel`, `isAggregation`), so a directive can skip barrel files.
```typescript [kubb.config.ts]
import { pluginFetch } from '@kubb/plugin-fetch'
pluginFetch({
output: {
path: 'clients',
banner: (meta) => (meta.isBarrel || meta.isAggregation ? '' : "'use server'"),
},
})
```
### output.footer {#output-footer}
Text added to the bottom of every generated file, like `banner` but for closing comments.
| | |
| --- | --- |
| Type | `string \| ((meta: BannerMeta) => string)` |
| Required | `false` |
Pair `banner: '/* eslint-disable */'` with `footer: '/* eslint-enable */'` to scope a lint disable to the generated file.
## group {#group}
Splits generated files into subfolders by the operation's tag or URL path, each under `{output.path}/{groupName}/`. Without `group`, every file lands directly in `output.path`.
| | |
| --- | --- |
| Type | `{ type: 'tag' \| 'path', name?: (context: { group: string }) => string }` |
| Required | `false` |
| Default | No grouping |
Switch the mode to see where these operations land on disk.
::grouping-diagram
::
`group` applies only to `output.mode: 'directory'`. Combining it with `output.mode: 'file'` stops the build with `KUBB_INVALID_PLUGIN_OPTIONS`.
```typescript [kubb.config.ts]
import { pluginTs } from '@kubb/plugin-ts'
pluginTs({ group: { type: 'tag' } }) // src/gen/types/pet/, src/gen/types/store/, ...
```
### group.type {#group-type}
Property used to assign each operation to a group. An operation with no tag goes in the `default` group.
| | |
| --- | --- |
| Type | `'tag' \| 'path'` |
| Required | `true` when `group` is set |
::field-group
:::field{name="'tag'"}
Uses the operation's first tag.
:::
:::field{name="'path'"}
Uses the first URL segment, such as `pet` for `/pet/{petId}`.
:::
::
### group.name {#group-name}
Turns the group key into the subfolder name, also used as the suffix on aggregate files. A `group.name` you pass always wins over the default.
| | |
| --- | --- |
| Type | `(context: { group: string }) => string` |
| Required | `false` |
| Default | `'tag'` groups camelCase the tag (`pet store` becomes `petStore`), `'path'` groups keep the raw URL segment |
```typescript [kubb.config.ts]
import { pluginTs } from '@kubb/plugin-ts'
pluginTs({
group: {
type: 'tag',
name: ({ group }) => `${group}Api`, // src/gen/types/petApi/
},
})
```
## include {#include}
Generates only the operations and schemas that match at least one entry, and skips the rest.
| | |
| --- | --- |
| Type | `Array` |
| Required | `false` |
| Default | Everything is generated |
Each entry filters by `tag`, `operationId`, `path`, `method`, `contentType`, or `schemaName`, with a `pattern` that is a string or a `RegExp`. A string is compiled with `new RegExp(pattern)`, so it is not an exact match: `pattern: 'pet'` also matches `'petType'` and `'superpet'`. Anchor it (`'^pet$'`) for an exact match. For `type: 'method'`, a string pattern is an uppercase HTTP method such as `'GET'`.
```typescript [Type definition]
export type Include = {
type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType' | 'schemaName'
pattern: string | RegExp
}
```
```typescript [kubb.config.ts]
import { pluginTs } from '@kubb/plugin-ts'
pluginTs({
include: [
{ type: 'tag', pattern: 'pet' },
{ type: 'path', pattern: /^\/store/ },
],
})
```
## exclude {#exclude}
Skips any operation or schema that matches at least one entry, the opposite of `include`.
| | |
| --- | --- |
| Type | `Array` |
| Required | `false` |
| Default | `[]` |
Entries use the same `type` and `pattern` fields as `include`. When both options match an item, `exclude` wins.
When a client plugin (`@kubb/plugin-fetch` or `@kubb/plugin-axios`) excludes operations, the plugins that build on it (`@kubb/plugin-react-query`, `@kubb/plugin-vue-query`, `@kubb/plugin-swr`, `@kubb/plugin-mcp`) skip those operations too, so you do not repeat the `exclude` list.
```typescript [kubb.config.ts]
import { pluginTs } from '@kubb/plugin-ts'
pluginTs({
exclude: [
{ type: 'tag', pattern: 'internal' },
{ type: 'operationId', pattern: /^deprecated_/ },
],
})
```
## override {#override}
Applies different plugin options to operations that match a pattern.
| | |
| --- | --- |
| Type | `Array` |
| Required | `false` |
| Default | `[]` |
Each entry takes the same `type` and `pattern` as `include`, plus an `options` object that accepts any plugin option except `override`, so rules cannot nest. Entries are checked top to bottom. The first match merges onto the plugin defaults, and later entries do not stack.
```typescript [Type definition]
export type Override = {
type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType' | 'schemaName'
pattern: string | RegExp
options: Omit, 'override'>
}
```
When a client plugin overrides `returnType`, `output`, or `group` for an operation, the plugins that build on it (`@kubb/plugin-react-query`, `@kubb/plugin-vue-query`, `@kubb/plugin-swr`, `@kubb/plugin-mcp`) follow those per-operation options.
```typescript [kubb.config.ts]
import { pluginTs } from '@kubb/plugin-ts'
pluginTs({
override: [
{
type: 'tag',
pattern: 'admin',
options: { output: { path: 'admin' }, enum: { type: 'enum' } },
},
],
})
```
## resolver {#resolver}
Overrides how the plugin names generated files and symbols. Members you omit keep the plugin's own resolver.
| | |
| --- | --- |
| Type | `ResolverPatch`, parameterized by each plugin with its own resolver type such as `ResolverPatch` |
| Required | `false` |
Every resolver shares the members below. A plugin adds namespaces of its own, such as `param` and `response` on `@kubb/plugin-ts` or `query` and `mutation` on `@kubb/plugin-react-query`, listed on that plugin's options page. Inside a method `this` is the full resolver, so `this.default.name(name)` reuses the built-in casing. See [Customize names and paths](/docs/5.x/how-to/resolvers) for how a patch layers over the default.
```typescript [Shared members]
type ResolverPatch = {
name?(name: string): string
file?: {
baseName?(params: { name: string; extname: string }): string
path?(params: { baseName: string; output: Output }): string
}
imports?(options: ResolveImportsOptions): Array
}
```
`name` cases an identifier, `file.baseName` and `file.path` decide where a file lands, and `imports` builds the import statements for the `$ref` schemas a node uses.
```typescript [kubb.config.ts]
import { pluginTs } from '@kubb/plugin-ts'
pluginTs({
resolver: {
name(name) {
return `${this.default.name(name)}Model`
},
},
})
```
## macros {#macros}
Rewrites AST nodes before they are printed, without forking the generator.
| | |
| --- | --- |
| Type | `Array` |
| Required | `false` |
| Default | `[]` |
Each [macro](/docs/5.x/how-to/macros) callback, such as `schema` or `operation`, receives the node and a context object and returns a replacement or `undefined` to leave it as is. Macros run in order, so a later one sees the output of an earlier one. The client plugins (`@kubb/plugin-fetch`, `@kubb/plugin-axios`, `@kubb/plugin-client`) run their built-in macros first and yours after them.
The built-in macros `macroDiscriminatorEnum`, `macroEnumName`, `macroRenameSchema` and `macroSimplifyUnion` are exported from `kubb/kit`. See [Macros](/docs/5.x/reference/kit/ast#macros) for the `Macro` type and its callbacks.
```typescript [kubb.config.ts]
import { ast } from 'kubb/kit'
import { pluginTs } from '@kubb/plugin-ts'
const macroUntagged = ast.defineMacro({
name: 'untagged',
operation(node) {
return node.tags?.length ? undefined : { ...node, tags: ['untagged'] }
},
})
pluginTs({ macros: [macroUntagged] })
```
---
- **Page:** Create aplugin · Kubb
- **Source:** https://kubb.dev/docs/5.x/tutorials/creating-plugins
- **Description:** Create and test a Kubb plugin.
# Create a plugin
Build a plugin that writes `listPets.ts` containing the method and path of one API operation, then add a configurable prefix. You need Node.js 22.12 or higher, npm, and TypeScript knowledge.
::steps{level="2"}
## Create a project {#_1-create-a-project}
```shell [Terminal]
mkdir kubb-first-plugin
cd kubb-first-plugin
npm init -y
npm pkg set type=module
npm install -D kubb typescript @types/node vitest
mkdir src
```
All authoring APIs come from `kubb/kit`, included with `kubb`.
## Add the specification {#_2-add-the-specification}
Create `petStore.yaml` in the project root:
```yaml [petStore.yaml]
openapi: 3.0.3
info:
title: Pets
version: 1.0.0
paths:
/pets:
get:
operationId: listPets
responses:
'200':
description: A list of pets
```
## Create the plugin {#_3-create-the-plugin}
`defineExtension` with `kind: 'plugin'` takes the plugin's `meta` and a `setup` function. Register a generator and resolver in `setup` with the `setResolver` and `addGenerator` [composables](/docs/5.x/reference/kit/plugins#setup-context), then return the plugin's options:
```typescript twoslash [src/plugin.ts]
import { addGenerator, ast, createResolver, defineExtension, defineGenerator, setResolver } from 'kubb/kit'
const resolver = createResolver({ pluginName: 'plugin-example' })
const operationsGenerator = defineGenerator({
name: 'operation-comments',
operation(node, ctx) {
const name = ctx.resolver.name(node.operationId)
return [
ast.factory.createFile({
baseName: `${name}.ts`,
path: `${ctx.root}/${name}.ts`,
sources: [
ast.factory.createSource({
nodes: [ast.factory.createText(`// ${node.method} ${node.path}\n`)],
}),
],
}),
]
},
})
export const pluginExample = defineExtension({
kind: 'plugin',
meta: { name: 'plugin-example', version: '1.0.0' },
setup(options) {
setResolver(resolver)
addGenerator(operationsGenerator)
return options
},
})
```
The `operation` handler writes a comment containing the operation's HTTP method and path.
## Generate {#_4-generate}
Register the plugin in your config:
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { pluginExample } from './src/plugin'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
plugins: [pluginExample()],
})
```
```shell [Terminal]
npx kubb generate
```
Read the generated file:
```shell [Terminal]
node -e "console.log(require('node:fs').readFileSync('src/gen/listPets.ts', 'utf8'))"
```
It contains a comment naming `GET` and `/pets`.
## Test the output {#_5-test-the-output}
Run an in-process build with memory storage and a small fixture. `createKubb` from `kubb` supplies the same adapter and parser defaults as `defineConfig`.
```typescript [src/plugin.test.ts]
import { describe, expect, it } from 'vitest'
import { createKubb } from 'kubb'
import { memoryStorage } from 'kubb/kit'
import { pluginExample } from './plugin'
const input = {
openapi: '3.0.3',
info: { title: 'Pets', version: '1.0.0' },
paths: {
'/pets': {
get: {
operationId: 'listPets',
responses: { '200': { description: 'A list of pets' } },
},
},
},
}
describe('pluginExample', () => {
it('emits an operation comment', async () => {
const { files, storage } = await createKubb({
input,
output: { path: './gen' },
storage: memoryStorage(),
plugins: [pluginExample()],
}).build()
const file = files.find((file) => file.baseName === 'listPets.ts')
expect(file).toBeDefined()
expect(await storage.readItem(file!.path)).toContain('/pets')
})
})
```
Run the test:
```shell [Terminal]
npx vitest run src/plugin.test.ts
```
Vitest reports one passing test. It checks the generated file in memory without writing to disk.
::
---
- **Page:** Commands · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/commands
- **Description:** Reference for every command and flag exposed by the kubb CLI including init, generate, validate, mcp, studio, add, update, and list.
# Commands
The `kubb` CLI is the main way to run Kubb. It reads your [configuration](/docs/5.x/reference/configuration) and runs the generation pipeline. It also scaffolds projects, validates specs, starts a Model Context Protocol server for AI clients, connects a project to Kubb Studio, and installs extensions from the [Kubb registry](/docs/5.x/reference/registry).
## Usage
```text [Terminal]
USAGE:
kubb [COMMANDS] []
COMMANDS:
[generate] [] Generate TypeScript types, API clients, React Query hooks, Zod schemas, and more from an OpenAPI specification. Reads kubb.config.ts by default. Pass an OpenAPI file path as the first argument to override the input without editing the config.
add [] Install a plugin, adapter, or parser from the Kubb registry at its reviewed version. A plugin is added to kubb.config.ts, an adapter or parser prints the code to add. Reads KUBB_REGISTRY to use another registry.
init [] Scaffold a kubb.config.ts and install plugins for code generation from an OpenAPI spec. Run without flags for interactive setup, or pass --input, --output, and --plugins to skip the prompts.
list [] List the installed Kubb extensions: their registry id, package, installed version, the version the Kubb registry pins, and whether an update exists.
mcp [] Start a Model Context Protocol (MCP) server that exposes Kubb code generation as tools for AI assistants. Once running, configure your AI client (Claude, Cursor, Windsurf, etc.) to connect to it — the assistant can then call kubb generate directly without leaving the chat.
studio [] Connect this project to Kubb Studio, or manage its pairing and snapshots.
update [] Update installed extensions to the version the Kubb registry pins. Pass ids to update only those, or --check to list the updates without installing.
validate [] Parse and validate an OpenAPI/Swagger file for structural correctness. Reports schema errors, missing required fields, and malformed references. Use this before running generate to catch spec issues early.
For more info, run any command with the `--help` flag:
kubb --help
kubb add --help
kubb init --help
kubb list --help
kubb mcp --help
kubb studio --help
kubb update --help
kubb validate --help
```
Run `kubb` with no command and it runs `kubb generate`. After the commands, `kubb --help` lists the `generate` arguments, options, and examples, which [`kubb generate`](/docs/5.x/reference/commands/generate) documents.
## Available commands
| Command | Description |
| ----------------------------- | ----------------------------------------------------------------- |
| [`kubb init`](/docs/5.x/reference/commands/init) | Scaffold a new Kubb project with an interactive wizard. |
| [`kubb generate`](/docs/5.x/reference/commands/generate) | Run the code-generation pipeline from your `kubb.config.ts`. |
| [`kubb validate`](/docs/5.x/reference/commands/validate) | Validate a Swagger/OpenAPI document without running the pipeline. |
| [`kubb mcp`](/docs/5.x/reference/commands/mcp) | Start a Model Context Protocol server for AI clients. |
| [`kubb studio`](/docs/5.x/reference/commands/studio) | Connect the project to Kubb Studio, or manage its pairing and snapshots. |
| [`kubb add`](/docs/5.x/reference/commands/add) | Install a plugin, adapter, or parser from the Kubb registry and add a plugin to the config. |
| [`kubb update`](/docs/5.x/reference/commands/update) | Move installed extensions to the version the Kubb registry pins. |
| [`kubb list`](/docs/5.x/reference/commands/list) | List the installed extensions, their versions, and available updates. |
## Environment variables
The CLI reads these shared environment variables.
| Variable | Type | Used by | Description |
| ------------------------ | --------- | -------- | --------------------------------------------------------------------------------- |
| `KUBB_DISABLE_TELEMETRY` | `boolean` | all | Turn off anonymous usage telemetry. Set it to `1` or `true`. |
| `DO_NOT_TRACK` | `boolean` | all | Standard opt-out convention. Set it to `1` or `true`. |
| `KUBB_HOME` | `string` | `studio` | Directory the CLI keeps its Studio state in. Defaults to `~/.kubb`. |
| `KUBB_TOKEN` | `string` | `studio snapshot` | Organization CI API key. Same as `--token`. |
| `KUBB_REGISTRY` | `string` | `add`, `update`, `list` | Base URL of the extension registry. Defaults to `https://kubb.dev/registry`. |
---
- **Page:** kubb add · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/commands/add
- **Description:** The add command installs a plugin, adapter, or parser from the Kubb extension registry at its reviewed version and adds a plugin to kubb.config.ts.
# kubb add
Run `kubb add` to install an extension from the [Kubb registry](/docs/5.x/reference/registry) at the version the registry pins. Without an id, it asks which extension to add. It checks that the extension supports your Kubb and Node.js versions, asks for confirmation, and installs the package as a dev dependency. For a plugin, it also adds the plugin to `kubb.config.ts`. For an adapter or parser, it prints the code to add.
Kubb detects the package manager (`npm`, `pnpm`, `yarn`, or `bun`) from your project.
## Usage
Search the registry and pick an extension:
```shell [Terminal]
kubb add
```
```text [Output]
◆ Select an extension to add:
│ Search: _
│ ● OpenAPI (kubb-labs/adapter-oas · adapter 5.2.0 · Reads OpenAPI and Swagger documents.)
│ ○ TypeScript parser
│ ○ React Query
│ ○ TypeScript
│ ○ Zod
│ ↑/↓ to select • Enter: confirm • Type: to search
```
Each row is the extension's display name. The focused row also shows its id, kind, pinned version, and description. Typing filters the rows on all of those, so `zod` keeps the Zod plugin and `adapter` keeps the adapters. Press Enter to continue with the usual confirmation.
Add an official plugin by its slug:
```shell [Terminal]
kubb add plugin-zod
```
Add a community plugin by its full id, without the confirmation:
```shell [Terminal]
kubb add acme/plugin-graphql --yes
```
Edit the config without installing the package:
```shell [Terminal]
kubb add plugin-zod --no-install
```
### npm or GitHub
An extension on npm installs as `@`. An extension pinned to a GitHub release installs as `github:/#`.
:::code-group
```shell [npm]
npx kubb add plugin-zod
# installs @kubb/plugin-zod@
```
```shell [GitHub]
npx kubb add acme/kubb-plugin-example
# installs github:acme/kubb-plugin-example#
```
:::
## Arguments
| Argument | Required | Description |
| -------- | -------- | ----------- |
| `` | `false` | Registry id as `/`, such as `kubb-labs/plugin-react-query`. A bare `` means `kubb-labs/`. Both parts use lowercase letters and digits joined by single hyphens. Without it, the CLI asks which extension to add. |
## Options
| Option | Default | Description |
| ------------------------------ | ------- | ----------- |
| `--config=`, `-c ` | | Path to the Kubb config to edit. Only used for plugins. Without it, the CLI looks for the same config files as `kubb generate`, in the current directory and then in each parent directory. |
| `--yes`, `-y` | `false` | Skip the confirmation. Needs an id. |
| `--no-install` | | Do not install the package. A plugin is still added to the config. |
> [!TIP]
> Pass `--yes` in scripts and CI, where no one can answer the prompt.
## Config changes
For a plugin, `kubb add` adds its import and a call at the end of the `plugins` array. A plugin already in the array is left alone.
When the config cannot be edited, the CLI prints `Could not edit : ` and the snippet to add by hand. This happens when `plugins` is not an array literal, or when the export name is already imported from another package.
## Environment variables
| Variable | Default | Description |
| --------------- | --------------------------- | ----------- |
| `KUBB_REGISTRY` | `https://kubb.dev/registry` | Base URL of the registry to read. It must start with `http://` or `https://`. Trailing slashes are removed. See [Host your own registry](/docs/5.x/reference/registry#host-your-own-registry). |
## Exit codes
`kubb add` exits with code 1 when the id is invalid or missing with `--yes`, the registry cannot be read or sends an invalid entry, the extension is incompatible, no config is found for a plugin, or the install fails. It exits with code 0 when you cancel at the prompt, and when it prints the snippet because the config could not be edited.
---
- **Page:** Generate your first client · Kubb
- **Source:** https://kubb.dev/docs/5.x/tutorials/quickstart
- **Description:** Generate and inspect a typed Axios client from a small OpenAPI specification.
# Generate your first client
Generate TypeScript types and an Axios client for one Petstore operation. You need Node.js 22.12 or higher and npm. You'll inspect the generated operation and its types.
::steps{level="2"}
## Create a project {#_1-create-a-project}
```shell [Terminal]
mkdir kubb-first-client
cd kubb-first-client
npm init -y
npm pkg set type=module
npm install -D kubb typescript @kubb/plugin-ts @kubb/plugin-axios
npm install axios
```
## Add the specification {#_2-add-the-specification}
Create `petStore.yaml` in the project root:
```yaml [petStore.yaml]
openapi: 3.0.3
info:
title: Petstore
version: 1.0.0
servers:
- url: https://petstore.swagger.io/v2
paths:
/pet/{petId}:
get:
operationId: getPetById
parameters:
- name: petId
in: path
required: true
schema:
type: integer
responses:
'200':
description: A pet
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
components:
schemas:
Pet:
type: object
required: [id, name]
properties:
id:
type: integer
name:
type: string
```
The `getPetById` operation accepts a pet ID and returns a pet with an ID and name.
## Configure generation {#_3-configure-generation}
Create `kubb.config.ts` beside the specification:
```typescript twoslash [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { pluginTs } from '@kubb/plugin-ts'
import { pluginAxios } from '@kubb/plugin-axios'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen', clean: true },
plugins: [
pluginTs({ output: { path: 'models' } }),
pluginAxios({ output: { path: 'clients' } }),
],
})
```
This configuration writes types to `src/gen/models` and the client to `src/gen/clients`.
> [!WARNING]
> Keep `src/gen` dedicated to generated files. `clean: true` removes its contents before each run.
## Generate the client {#_4-generate-the-client}
```shell [Terminal]
npx kubb generate
```
Kubb reports a successful build and writes this tree. Open `src/gen/clients/getPetById.ts` and notice that `getPetById` accepts typed path parameters and returns a typed result. Its imported types live in `src/gen/models`.
:::file-tree
---
tree:
- name: src
type: dir
children:
- name: gen
type: dir
children:
- name: .kubb
type: dir
- name: clients
type: dir
children:
- name: getPetById.ts
- name: models
type: dir
children:
- name: GetPetById.ts
- name: Pet.ts
---
:::
The `.kubb` directory holds shared client and serialization helpers.
## Regenerate after a change {#_5-regenerate-after-a-change}
Add a `tag` property to the `Pet` schema in `petStore.yaml`, alongside `id` and `name`:
```yaml [petStore.yaml — properties]
tag:
type: string
```
Run `npx kubb generate` again and open `src/gen/models/Pet.ts`. It now includes an optional `tag` field because `tag` is not listed in the schema's `required` array. The client continues to import the regenerated types.
You now have a typed client and have seen how a specification change flows into its output.
::
## Continue
::card-group
:::card{title="Call generated operations" icon="i-iconoir-code" to="/extensions/kubb-labs/plugin-axios/guides/calling-operations"}
Use the generated Axios client. [Configure its host](/extensions/kubb-labs/plugin-axios/guides/base-url) for your API.
:::
:::card{title="Configure generation" icon="i-iconoir-settings" to="/docs/5.x/how-to/recipes"}
Add React or Vue hooks, validation, and mocks.
:::
:::card{title="Configuration reference" icon="i-iconoir-bookmark" to="/docs/5.x/reference/configuration"}
Look up specification versions, options, and config formats.
:::
::
---
- **Page:** kubb validate · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/commands/validate
- **Description:** The validate command checks that a Swagger/OpenAPI document is valid without running the full pipeline.
# kubb validate
Run `kubb validate` to check that a Swagger/OpenAPI document is valid without running the pipeline. Use it to catch errors early in CI or before you commit a spec change.
::terminal
---
command: kubb validate ./petStore.yaml
output:
- ✅ Validation success
---
::
The input can also be a URL, such as `https://petstore3.swagger.io/api/v3/openapi.json`.
## Arguments
| Argument | Required | Description |
| --------- | -------- | -------------------------------------------------------- |
| `` | `true` | Path or URL to the Swagger/OpenAPI document to validate. |
> [!TIP]
> `kubb validate` exits with a non-zero status code when the spec is invalid. Use it as a pre-commit hook or CI step to fail the build.
---
- **Page:** Adapters · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/kit/adapters
- **Description:** defineExtension with kind adapter builds an adapter that converts an input specification into the universal AST. Covers the Adapter interface, the built-in OpenAPI adapter, and writing your own.
# Adapters
An adapter converts an input specification into the shared AST.
> [!TIP]
> For OpenAPI 2.0, 3.0, and 3.1 use the official [`@kubb/adapter-oas`](/extensions/kubb-labs/adapter-oas). Kubb picks it for you when you import `defineConfig` from the `kubb` package. Write a custom adapter only when you target a different specification such as AsyncAPI, GraphQL, JSON Schema, or gRPC.
## `defineExtension`
`defineExtension` with `kind: 'adapter'` takes a definition object and returns a factory that types the adapter's options. `setup` turns the user's options into the resolved options, and `build` returns the adapter's `document`, `parse`, and `validate` for them. Without `setup`, the user's options are the resolved options.
A minimal adapter declares a name and returns an empty [`InputNode`](/docs/5.x/explanation/architecture#ast). An empty AST emits nothing, so fill `schemas` and `operations` from your spec next.
```typescript twoslash [adapterCustom.ts]
import { ast, defineExtension } from 'kubb/kit'
import type { AdapterFactoryOptions } from 'kubb/kit'
type AdapterCustom = AdapterFactoryOptions<'adapter-custom', { strict?: boolean }, { strict: boolean }>
export const adapterCustom = defineExtension({
kind: 'adapter',
meta: { name: 'adapter-custom' },
setup: (options) => ({ strict: options.strict ?? false }),
build: () => ({
document: null,
async parse(_source) {
return ast.factory.createInput({ schemas: [], operations: [] })
},
async validate() {
// Throw or call ctx.error here when the spec is invalid.
},
}),
})
```
### `createAdapter` (deprecated)
> [!WARNING]
> `createAdapter` is deprecated. Use `defineExtension` with `kind: 'adapter'` instead.
`createAdapter` takes the same definition object as `defineExtension`, without `kind`. To move over, rename the call and add `kind: 'adapter'`. See [Extensions](./extensions#define-extension).
Pass the adapter to your config:
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { adapterCustom } from './adapterCustom.ts'
export default defineConfig({
input: './my-spec.json',
output: { path: './src/gen' },
adapter: adapterCustom({ strict: true }),
plugins: [],
})
```
## Adapter anatomy
Every adapter the factory returns matches the `Adapter` interface from [`kubb/kit`](/docs/5.x/reference/kit):
| Property | Type | Required | Purpose |
| ---------- | ------------------------------------------------------------------------ | -------- | --------------------------------------------------------------------------------------------- |
| `name` | `string` | Yes | Unique adapter identifier, filled from `meta.name`. Convention is `adapter-`. |
| `options` | `TResolvedOptions` | Yes | Adapter options after defaults are applied. |
| `document` | `TDocument \| null` | Yes | The raw parsed source document, for plugins that need direct access. `null` before `parse()`. |
| `parse` | `(source: AdapterSource) => InputNode \| Promise` | Yes | Convert the spec into the [universal AST](/docs/5.x/explanation/architecture#ast). |
| `validate` | `(input: string, options?: { throwOnError?: boolean }) => Promise` | Yes | Validate the document at a path or URL without running the full pipeline. |
Cross-references need no adapter hook: every plugin resolves `$ref` imports through [`resolver.imports`](/docs/5.x/reference/kit/resolvers#imports), which defaults each ref to its pointer's last segment. An adapter that renames a schema (for example to break a name collision) stamps `targetName` on every ref node pointing at it, so those imports pick up the emitted name. Refs that keep their segment name need no stamp.
> [!IMPORTANT]
> Throw from `parse()` with a clear, user-facing message when the input is invalid.
## Adapter naming convention
Name adapters like plugins, so [`getResolver`](./generators#definegenerator), the registry, and the docs can find them:
| Surface | Pattern | Example |
| ----------------------------- | -------------------------------------------------- | ------------------- |
| npm package | `@/adapter-` or `kubb-adapter-` | `@kubb/adapter-oas` |
| Adapter runtime name | The spec identifier (lowercase) | `'oas'` |
| Factory export | `adapter` (camelCase) | `adapterOas` |
| Name constant | `adapterName` | `adapterOasName` |
| `AdapterFactoryOptions` alias | `Adapter` (PascalCase) | `AdapterOas` |
Export a `satisfies`-typed name constant so consumers can reuse the runtime name.
---
- **Page:** Extension docs · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/kit/extension-docs
- **Description:** Reference for the docs folder a Kubb plugin, adapter, or parser ships on npm. Covers the files kubb.dev renders, titles and descriptions, guide ids, and the Markdown that renders.
# Extension docs
An extension ships its docs in a `docs/` folder at the package root, next to [`kubb-extension.json`](./manifest). The [registry](/docs/5.x/reference/registry#detail) reads the folder from the npm tarball of the pinned version, and kubb.dev renders it under `/extensions//`. List `docs` in `files` in `package.json` so npm ships it.
## Files
| File | Page on kubb.dev | Required |
| --- | --- | --- |
| `docs/overview.md` | `/extensions//`, also the summary in Studio | Yes |
| `docs/options.md` | `/extensions///options` | No |
| `docs/guides/.md` | `/extensions///guides/` | No |
The registry ignores other files in `docs/`. It skips a file larger than 256 KiB and reports it.
## Title and description
Start each file with a `#` title on its first line. The first paragraph after the title is the description, which guide cards, search, and the meta description show. Files have no frontmatter.
## Guides
Name each guide file in kebab case, such as `base-url.md`. Its id is the file name without `.md`. Guides appear in file name order, at most 50. A guide without a title, a description, or a kebab-case id is not listed.
## Markdown
Write plain Markdown, and use absolute `https://` URLs for links and images. A code fence can carry a title, such as ` ```typescript [kubb.config.ts] `. These also render:
- The callouts `> [!NOTE]`, `> [!TIP]`, `> [!IMPORTANT]`, and `> [!WARNING]`.
- The components `::code-group`, `::field-group` with `:::field`, `::steps`, `::code-collapse`, and `::tabs` with `:::tabs-item`.
kubb.dev does not render raw HTML, `` lines, twoslash code fences, or other components. Validation reports each one before a version is approved.
## Overview
`overview.md` is the extension's page on kubb.dev. Cover these points in order, and add headings only when they help:
1. What the extension is and does, in one or two short paragraphs.
2. How it works, only when that is not obvious.
3. The setup it needs, such as other plugins or peer packages.
4. Options worth explaining and known limits.
When the package runs an install script, uses the network, or touches files outside its output path, say so in the overview.
Use sentence case, plain language, and no em dashes. Leave out install commands, badges, a changelog, license text, and marketing. The page already shows how to install, and validation fails for an overview that contains `kubb add`, `npm install`, `npm i`, `pnpm add`, or `yarn add`.
---
- **Page:** Engine · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/kit/engine
- **Description:** The programmatic engine from the kubb package. Covers createKubb, the Kubb instance, BuildOutput, and the Diagnostics helpers that narrow a build's problems.
# Engine
Import `createKubb` from the `kubb` package to run a build from your own code. For the config file shape and the defaults the package applies, see [Configuration](/docs/5.x/reference/configuration).
## `createKubb` {#createkubb}
`createKubb` accepts a `UserConfig` and returns a `Kubb` instance. Call `.safeBuild()` to run the pipeline and read the problems back from `BuildOutput`, or `.build()` to throw instead.
Reach for `createKubb` when you orchestrate several builds, inspect diagnostics, or feed Kubb output into a larger toolchain. It applies the same defaults as `defineConfig`, so a shared config generates the same files from the CLI and from a script. Import it from `@kubb/core` for a bare engine without package defaults.
```typescript twoslash [build.ts]
// @module: esnext
import { createKubb } from 'kubb'
import { Diagnostics } from 'kubb/kit'
import { pluginTs } from '@kubb/plugin-ts'
import { pluginAxios } from '@kubb/plugin-axios'
const kubb = createKubb({
input: './petStore.yaml',
output: { path: './gen' },
plugins: [pluginTs(), pluginAxios()],
})
const { files, storage, diagnostics } = await kubb.safeBuild()
if (Diagnostics.hasError(diagnostics)) {
for (const diagnostic of diagnostics.filter(Diagnostics.isProblem)) {
if (diagnostic.severity === 'error') {
console.error(`${diagnostic.plugin ?? 'kubb'}: ${diagnostic.message}`)
}
}
process.exit(1)
}
for (const { plugin, duration } of diagnostics.filter(Diagnostics.isPerformance)) {
console.log(`${plugin}: ${duration}ms`)
}
console.log(`Generated ${files.length} files`)
const paths = await storage.readKeys()
paths.forEach((path) => console.log(` ${path}`))
```
### `Kubb` instance members
| Member | Type | Description |
| -------------- | ------------------------------------------------- | ----------- |
| `.setup()` | `() => Promise` | Initializes the driver and storage. The build methods call it when needed. |
| `.safeBuild()` | `() => Promise` | The canonical call. Runs the pipeline and collects problems in `BuildOutput.diagnostics` instead of throwing. |
| `.build()` | `() => Promise` | Runs `safeBuild()` and throws an `AggregateError` holding every error diagnostic when one has `severity: 'error'`. |
| `.generate()` | `(options?) => Promise` | Runs one full generation, including the `kubb:generation:*` hooks and the optional `processOutput` pass. Never throws on a build error. Returns `{ success, files, diagnostics }`. |
| `.dispose()` | `() => void` | Releases the driver. The instance also implements `Symbol.dispose`, so `using kubb = createKubb(config)` disposes it for you. |
| `.hooks` | `Hookable` | Read-only. Shared hook emitter. Call `.hook(name, handler)` before a build to listen. See [lifecycle hooks](./hooks). |
| `.config` | `Config` | Read-only. Resolved config, available right after `createKubb`. |
| `.storage` | `Storage` | Read-only. Final source code keyed by absolute path. Available after `setup()`, throws before. |
| `.driver` | driver handle | Advanced plugin driver, available after `setup()`. Throws before. |
### `BuildOutput` fields {#buildoutput-fields}
| Field | Type | Description |
| ------------- | ------------------- | ----------- |
| `files` | `Array` | Generated files with paths, names, and content |
| `storage` | `Storage` | Generated source code behind the `Storage` API |
| `driver` | driver handle | Plugin driver for introspection |
| `diagnostics` | `Array` | Problems collected during the build, plus a `performance` diagnostic per plugin |
Each problem diagnostic carries a `code`, a `severity` (`error`, `warning`, or `info`), a `message`, and the `plugin` that produced it. A failed plugin keeps its original error on `cause`. A `performance` diagnostic (`kind: 'performance'`) carries a `duration` in milliseconds.
> [!WARNING]
> After `safeBuild()`, check `Diagnostics.hasError(diagnostics)` before you process files. Plugins can fail without `safeBuild()` throwing.
## `Diagnostics` {#diagnostics}
`Diagnostics` from `kubb/kit` builds and narrows the structured errors a build collects. A plugin or adapter throws a `Diagnostics.Error` instead of a bare `Error` to attach a stable code, a severity, and a location. The codes are listed in the [diagnostics reference](/docs/5.x/reference/diagnostics).
| Member | Purpose |
| --------------------------- | ------- |
| `Diagnostics.Error` | Error class (`DiagnosticError`) that carries a `ProblemDiagnostic` with `code`, `severity`, `message`, and `location` |
| `Diagnostics.report` | Collects a diagnostic into the running build without throwing. Use a `warning` or `info` severity for non-fatal issues |
| `Diagnostics.from` | Coerces any thrown value into a `ProblemDiagnostic`. Anything that is not a `Diagnostics.Error` becomes `KUBB_UNKNOWN` |
| `Diagnostics.hasError` | `true` when any diagnostic has `severity: 'error'` |
| `Diagnostics.isProblem` | Narrows to the `problem` kind |
| `Diagnostics.isPerformance` | Narrows to the `performance` kind, which carries a per-plugin `duration` |
| `Diagnostics.isUpdate` | Narrows to the `update` kind, emitted when a newer Kubb version exists |
| `Diagnostics.count` | Totals errors, warnings, and infos |
| `Diagnostics.explain` | Returns the catalog entry (title, fix, docs URL) for a code |
```typescript twoslash [adapter.ts]
import { Diagnostics } from 'kubb/kit'
throw new Diagnostics.Error({
code: Diagnostics.code.refNotFound,
severity: 'error',
message: 'Could not find a definition for #/components/schemas/Pet.',
location: { kind: 'schema', pointer: '#/components/schemas/Pet', ref: '#/components/schemas/Pet' },
})
```
---
- **Page:** Extensions · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/kit/extensions
- **Description:** defineExtension defines a plugin, an adapter, or a parser in kubb/kit. Covers kind, ExtensionMeta, compatibility ranges, plugin dependencies with version ranges, and the kind and meta that every extension factory carries.
# Extensions
Plugins, adapters, and parsers are all extensions. `defineExtension` takes a definition object with a `kind` and `meta`, and returns a factory that the config calls with the user's options. The fields on this page work the same for every kind.
## `defineExtension` {#define-extension}
`kind` picks what the definition defines, and the other fields follow that kind:
| `kind` | Defines | Other fields | Reference |
| ----------- | ------------------------------------------------ | --------------------------------------------- | ------------------------ |
| `'plugin'` | A plugin that generates code from the AST. | `setup`, `dependencies`, `enforce`, `hooks` | [Plugins](./plugins) |
| `'adapter'` | An adapter that reads the input into the AST. | `setup`, `build` | [Adapters](./adapters) |
| `'parser'` | A parser that prints files to source text. | `build` | [Parsers](./parsers) |
```typescript twoslash [plugin-example.ts]
import { defineExtension } from 'kubb/kit'
export const pluginExample = defineExtension({
kind: 'plugin',
meta: { name: 'plugin-example' },
})
```
> [!WARNING]
> `definePlugin`, `defineParser`, and `createAdapter` are deprecated. Each takes the same definition object as `defineExtension`, without `kind`. Pass the object to `defineExtension` and add `kind: 'plugin'`, `'parser'`, or `'adapter'`.
## `meta` {#meta}
`meta` holds the extension's identity and the Kubb and Node.js versions it supports. Kubb reads `name` and `compatibility` at runtime. Studio, the kubb.dev registry, and the docs read the rest.
```typescript twoslash [plugin-example.ts]
import { defineExtension } from 'kubb/kit'
export const pluginExample = defineExtension({
kind: 'plugin',
meta: {
name: 'plugin-example',
version: '1.0.0',
displayName: 'Example',
description: 'Adds a comment to every generated schema.',
compatibility: { kubb: '>=5.7.0', node: '>=22' },
},
})
```
| Property | Type | Description |
| --------------- | ----------------------------------- | ----------- |
| `name` | `string` | Unique name. The plugin's or parser's own `name` is deprecated in favor of it, and optional when `meta.name` is set. Required. |
| `version` | `string` | Package version. Plugins that depend on this one check their `version` range against it. |
| `displayName` | `string` | Human-readable name, such as `'TypeScript'`. |
| `description` | `string` | One-sentence summary of what the extension generates or does. |
| `category` | `string` | Registry category, such as `'types'` or `'client'`. |
| `icon` | `{ light: string; dark?: string }` | Icon URLs, with an optional variant for dark backgrounds. |
| `media` | `Array` | Screenshots or videos, as HTTPS URLs. |
| `tags` | `Array` | Search keywords for the registry. |
| `compatibility` | `{ kubb?: string; node?: string }` | Semver ranges for `@kubb/core` and Node.js. |
| `docs` | `string` | URL of the extension's docs page. |
| `issues` | `string` | URL of the extension's issue tracker. When the extension crashes, Kubb prints it as the `report:` link, so users report the bug to you instead of to Kubb. |
Read `version` from your `package.json` so it stays in sync with what you publish:
```typescript
import { version } from '../package.json'
```
A package that ships a [`kubb-extension.json`](./manifest) imports `compatibility` from it, so the ranges live in one file. See [Import `compatibility` into `meta`](./manifest#import-compatibility-into-meta).
### Compatibility checks
Before any plugin runs, Kubb checks each plugin's and parser's `meta.compatibility` against the running `@kubb/core` and Node.js versions. A mismatch fails the run with [`KUBB_INCOMPATIBLE_EXTENSION`](/docs/5.x/reference/diagnostics#kubb-incompatible-extension), which names the extension and the version that is running. Kubb compares prerelease versions like regular ones.
## `dependencies` {#dependencies}
A plugin's `dependencies` lists the plugins it builds on, keyed by name. They run first when the config has them. Each entry decides what happens when a plugin is missing or has the wrong version:
```typescript twoslash [plugin-example.ts]
import { defineExtension } from 'kubb/kit'
export const pluginExample = defineExtension({
kind: 'plugin',
meta: { name: 'plugin-example' },
dependencies: {
'plugin-ts': { version: '>=5.0.0' },
'plugin-zod': { optional: true },
},
})
```
| Entry field | Type | Description |
| ----------- | --------- | ----------- |
| `version` | `string` | Semver range the dependency's `meta.version` must satisfy. Kubb skips the check when the dependency has no `meta.version`. |
| `optional` | `boolean` | When `true`, a missing plugin is skipped. An installed one still has its `version` checked. |
Kubb checks the record before any plugin runs:
- A missing entry without `optional: true` fails with [`KUBB_MISSING_DEPENDENCY`](/docs/5.x/reference/diagnostics#kubb-missing-dependency).
- A `meta.version` outside the `version` range fails with [`KUBB_INCOMPATIBLE_DEPENDENCY`](/docs/5.x/reference/diagnostics#kubb-incompatible-dependency).
When a dependency depends on the user's options, pass a function. It receives the options and returns the record:
```typescript twoslash [plugin-example.ts]
import { defineExtension, type PluginType } from 'kubb/kit'
type PluginExample = PluginType<'plugin-example', { parser?: 'data' | 'faker' }>
export const pluginExample = defineExtension({
kind: 'plugin',
meta: { name: 'plugin-example' },
dependencies: (options) => ({
'plugin-ts': {},
...(options.parser === 'faker' ? { 'plugin-faker': {} } : {}),
}),
})
```
> [!NOTE]
> An array, such as `dependencies: ['plugin-ts']`, still works. It only orders plugins, so a missing one is skipped and versions are not checked.
## Factory statics
Every factory `defineExtension` returns carries `kind` (`'plugin'`, `'adapter'`, or `'parser'`) and `meta`, so tools can read an extension's metadata without calling the factory or knowing its options:
```typescript
pluginExample.kind // 'plugin'
pluginExample.meta.name // 'plugin-example'
```
A factory built from a deprecated factory function has no `meta` on it, because Kubb only learns it by calling the factory. The plugin or parser it returns still has `meta`, which falls back to `{ name }`.
---
- **Page:** Generators · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/kit/generators
- **Description:** defineGenerator declares a named generator unit that walks the AST and emits files. Covers the schema, operation, and operations methods and the GeneratorContext passed to each.
# Generators
## `defineGenerator` {#definegenerator}
`defineGenerator` declares a named generator unit consumed by a plugin. Generators walk the [AST](/docs/5.x/explanation/architecture#ast) and emit files. Kubb calls each method for the matching node type.
Each generator method returns `TElement | Array | void`. Returning a renderer element (for example JSX from [`kubb/jsx`](/docs/5.x/reference/jsx)) requires a `renderer` factory on the generator.
```typescript twoslash [my-generator.ts]
import { ast, defineGenerator } from 'kubb/kit'
const myGenerator = defineGenerator({
name: 'my-generator',
operation(node, ctx) {
return [
ast.factory.createFile({
baseName: `${node.operationId}.ts`,
path: `./${node.operationId}.ts`,
sources: [
ast.factory.createSource({
nodes: [ast.factory.createText(`export const op = '${node.operationId}'`)],
}),
],
}),
]
},
})
```
### Generator methods
| Method | Input | Output | When to use |
| -------------- | --------------------------------------- | ------------------------------------- | ---------------------------------------------------------------- |
| `schema()` | `SchemaNode` (per data schema) | `TElement \| Array \| void` | Generate types, validators, factories. Called once per schema |
| `operation()` | `OperationNode` (per API operation) | `TElement \| Array \| void` | Generate hooks, clients, handlers. Called once per operation |
| `operations()` | `Array` (all operations) | `TElement \| Array \| void` | Generate index or barrel files. Called once after all operations |
### Scoping with `match` {#match}
Add a `match(node, ctx)` predicate to skip `schema` or `operation` for nodes a generator does not apply to. A `false` result skips that node. Omitting `match` runs the generator for every node. `match` does not filter `operations()`.
```typescript twoslash [scoped-generator.ts]
import { ast, defineGenerator } from 'kubb/kit'
const getOnlyGenerator = defineGenerator({
name: 'get-only-generator',
match(node, ctx) {
return node.kind === 'Operation' && ast.isHttpOperationNode(node) && node.method.toLowerCase() === 'get'
},
operation(node, ctx) {
// node is already known to be a GET operation here
return
},
})
```
### `GeneratorContext` properties (the `ctx` argument passed to each method)
| Property | Type | Purpose |
| --------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ctx.config` | `Config` | Resolved Kubb configuration |
| `ctx.root` | `string` | Absolute path to the output directory for the current plugin |
| `ctx.options` | `TResolvedOptions` | Per-node resolved options (after exclude/include/override filtering) |
| `ctx.plugin` | `Plugin` | The owning plugin descriptor |
| `ctx.resolver` | `Resolver` | Resolver for the current plugin |
| `ctx.driver` | `KubbDriver` | Plugin driver for cross-plugin access |
| `ctx.hooks` | `Hookable` | Event bus for `KubbHooks` events |
| `ctx.adapter` | `Adapter` | The adapter that parsed the input spec |
| `ctx.meta` | `InputMeta` | Document metadata from the adapter. Carries `title`, `version`, `baseURL`, every declared `servers` entry and `securitySchemes` entry, and the pre-computed `circularNames` and `enumNames` arrays. |
| `ctx.cache` | `NodeCache` | Cache scoped to the node being generated, shared by every plugin generating from that node in the current pass. Exposes `readItem`, `writeItem`, and `ensureItem` |
| `ctx.addFile()` | `(...files: FileNode[]) => Promise` | Add files, skipping any that already exist |
| `ctx.upsertFile()` | `(...files: FileNode[]) => Promise` | Add or merge files (concatenates sources and imports) |
| `ctx.getPlugin()` | `(name: string) => Plugin \| undefined` | Get a plugin by name |
| `ctx.requirePlugin()` | `(name: string) => Plugin` | Get a plugin by name or throw a descriptive error |
| `ctx.getResolver()` | `(name: string) => Resolver` | Get a resolver by plugin name |
| `ctx.info()` | `(message: string, options?: { code?, help?, location? }) => void` | Emit an info message via the build event system |
| `ctx.warn()` | `(message: string, options?: { code?, help?, location? }) => void` | Emit a warning via the build event system. `options` sets the fix and the source pointer |
| `ctx.error()` | `(error: string \| Error, options?: { code?, help?, location? }) => void` | Emit an error via the build event system. A `Diagnostics.Error` keeps its code, help, and location |
---
- **Page:** Extension manifest · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/kit/manifest
- **Description:** Reference for kubb-extension.json, the manifest a Kubb plugin, adapter, or parser ships on npm. Covers every top-level field, the compatibility rule, validation, and importing compatibility into meta.
# Extension manifest
`kubb-extension.json` describes an extension package. It sits at the package root and ships on npm. The [Kubb registry](/docs/5.x/reference/registry), [`kubb add`](/docs/5.x/reference/commands/add), [`kubb init`](/docs/5.x/reference/commands/init), [`kubb list`](/docs/5.x/reference/commands/list), and the [Studio](/docs/5.x/reference/commands/studio#plugins-in-studio) agent read it. Generation does not: at runtime Kubb reads the extension's [`meta`](./extensions#meta).
The JSON Schema is [`https://kubb.dev/schemas/kubb-extension.json`](https://kubb.dev/schemas/kubb-extension.json). Set it as `$schema` to get validation and completion in your editor.
```json [kubb-extension.json]
{
"$schema": "https://kubb.dev/schemas/kubb-extension.json",
"kind": "plugin",
"name": "plugin-example",
"export": "pluginExample",
"displayName": "Example",
"description": "Writes a comment with the HTTP method and path of every operation.",
"category": "documentation",
"icon": { "light": "https://example.com/icon.svg" },
"tags": ["comments", "operations"],
"docs": "https://github.com/acme/kubb-plugin-example#readme",
"maintainers": [{ "name": "Acme", "github": "acme" }],
"compatibility": { "kubb": ">=5.8.3", "node": ">=22" },
"options": [
{
"key": "prefix",
"path": ["prefix"],
"label": "Prefix",
"description": "Text written at the start of every comment.",
"type": "text"
}
]
}
```
## Fields
Readers ignore unknown top-level keys.
::field-group
### `$schema`
:::field{type="string"}
The JSON Schema URL, `https://kubb.dev/schemas/kubb-extension.json`. Only editors read it.
:::
### `kind`
:::field{type="'plugin' | 'adapter' | 'parser'" required}
What the package extends. `kubb add` adds a `plugin` to the config and prints the code for an `adapter` or `parser`. Studio builds a form for every kind: plugins can be switched on and off, while the adapter and the parsers are the ones the config registers.
:::
### `name`
:::field{type="string" required}
The extension's `meta.name`, such as `plugin-zod`, `oas`, or `typescript`. Kubb skips a manifest whose `name` is not shaped like an npm package name: lowercase letters, digits, `.`, `_`, `~`, and `-`, with an optional `@scope/`.
:::
### `export`
:::field{type="string" required}
The factory export users call in `kubb.config.ts`, such as `pluginZod`. It must be a JavaScript identifier. `kubb add` imports this name, and the Studio agent calls it.
:::
### `displayName`
:::field{type="string" required}
The human-readable name, such as `Zod`.
:::
### `description`
:::field{type="string" required}
One sentence on what the extension does.
:::
### `category`
:::field{type="string"}
Category for filtering, such as `validation`. The registry replaces it with the main category the reviewer picks from [the category list](/docs/5.x/reference/registry#categories).
:::
### `icon`
:::field{type="{ light: string; dark?: string }"}
Icon URLs for light and dark backgrounds. Both must use HTTPS. Studio shows a generic icon when the manifest has none.
:::
### `media`
:::field{type="Array"}
Screenshots or videos, as HTTPS URLs.
:::
### `tags`
:::field{type="Array"}
Search keywords.
:::
### `docs`
:::field{type="string"}
Documentation URL, using HTTPS.
:::
### `maintainers`
:::field{type="Array<{ name: string; github?: string }>"}
The people who maintain the extension, shown on its kubb.dev page. Each entry needs a `name`, such as `Stijn Van Hulle`, and can add a `github` username, such as `stijnvanhulle`.
:::
### `dependencies`
:::field{type="Array"}
Names of the extensions that must be in the same config, such as `["plugin-ts"]`. kubb.dev lists them on the extension's page, and `kubb init` checks that each one is chosen. Generation does not read them: at runtime Kubb uses the plugin's own [`dependencies`](./extensions#dependencies).
:::
### `optionalDependencies`
:::field{type="Array"}
Names of the extensions the plugin uses when they are in the same config, or needs only for some option values. `@kubb/plugin-msw` lists `["plugin-faker"]`, because it needs `@kubb/plugin-faker` only with `parser: 'faker'`. They match the entries marked `optional: true` or picked from the options in the plugin's runtime [`dependencies`](./extensions#dependencies). kubb.dev lists them below the dependencies. `kubb init` does not require them.
:::
### `compatibility`
:::field{type="{ kubb?: string; node?: string }"}
Semver ranges for Kubb (`@kubb/core`) and Node.js, such as `{ "kubb": ">=5.8.3", "node": ">=22" }`. Only these two keys are allowed. Any other key makes the manifest invalid, so a typo such as `nodejs` cannot skip a check.
`kubb add` and `kubb update` check the ranges before they install. Kubb checks the same ranges at runtime through `meta.compatibility`, so [import it from the manifest](#import-compatibility-into-meta).
:::
### `role`
:::field{type="'client' | 'consumer'"}
Plugins only. `client` provides the HTTP client runtime, like `@kubb/plugin-fetch`. `consumer` generates code that calls a client but ships none, like `@kubb/plugin-react-query`. Studio and `kubb init` use it to require a client plugin next to a consumer.
:::
### `options`
:::field{type="Array"}
Form fields Kubb Studio shows for the extension. The [JSON Schema](https://kubb.dev/schemas/kubb-extension.json) describes each field.
:::
::
## Validation
Kubb and the registry check a manifest at different points:
| Reader | Checks | On failure |
| --- | --- | --- |
| `kubb add`, `kubb init`, `kubb update`, `kubb list`, the Studio agent | The required fields are set and well formed. Each `maintainers` entry has a `name`. Each `dependencies` and `optionalDependencies` entry is an extension name. `role` is `client` or `consumer`. `compatibility` holds only `kubb` and `node` string ranges. `options` is an array. | The manifest is skipped. |
| The registry | The JSON Schema, unique option keys, `choices` on every `select`, and a `select` default that equals one of its choices. | The review pull request lists the problem, and the weekly bump keeps the previous pin. |
## Import `compatibility` into `meta` {#import-compatibility-into-meta}
Keep the ranges in one place. Import only `compatibility` from the manifest into `meta`, so a bundler leaves the rest of the file, including `options`, out of your build:
```typescript [src/plugin.ts]
import { defineExtension } from 'kubb/kit'
import { compatibility } from '../kubb-extension.json'
import { version } from '../package.json'
export const pluginExampleName = 'plugin-example'
export const pluginExample = defineExtension({
kind: 'plugin',
meta: { name: pluginExampleName, version, compatibility },
setup(options) {
return options
},
})
```
Keep `name` as a typed constant. A JSON import widens it to `string`. Named imports from JSON need a bundler, such as tsdown, that inlines them. With plain `tsc` and `"module": "NodeNext"`, write the same ranges in `meta.compatibility` instead.
---
- **Page:** Lifecycle hooks · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/kit/hooks
- **Description:** Every kubb:* hook a build fires, its payload, and when it fires. Listen with kubb.hooks.hook(name, handler) or from a plugin's hooks map.
# Lifecycle hooks
Kubb runs on one shared, typed hook emitter, and every phase of a build fires a `kubb:*` hook on it. Plugins listen through their [`hooks`](./plugins) map. Outside code listens through `kubb.hooks`.
Every hook name and its payload lives in the `KubbHooks` type. Handlers can be async, and Kubb awaits each one.
## Listening
Attach a listener with `kubb.hooks.hook(name, handler)` before you call `build()`.
```ts
import { createKubb } from 'kubb'
const kubb = createKubb({
input: './petStore.yaml',
output: { path: './gen' },
})
kubb.hooks.hook('kubb:plugin:end', ({ plugin, duration }) => {
console.log(`${plugin.name} finished in ${duration}ms`)
})
kubb.hooks.hook('kubb:build:end', ({ files }) => {
console.log(`Generated ${files.length} files`)
})
await kubb.build()
```
## Firing order
A full generation run fires the hooks in this order.
::lifecycle-timeline
::
## Generation run
These wrap a full run. A direct `.build()` or `.safeBuild()` does not fire them.
| Hook | Payload | When it fires |
| ------------------------ | ------------------------------------------------------------- | ------------------------------------------------------ |
| `kubb:lifecycle:start` | `{ version }` | The bundler plugin starts, before anything else |
| `kubb:generation:start` | `{ config }` | A run begins, before setup |
| `kubb:setup:start` | none | Before the driver and storage are initialized |
| `kubb:setup:end` | none | After setup, before the build pipeline |
| `kubb:generation:end` | `{ config, storage, status, diagnostics, filesCreated, hrStart }` | The run finishes, after the output passes |
| `kubb:generation:summary`| `KubbGenerationSummaryContext` | After the run, with the summary the reporters render |
| `kubb:lifecycle:end` | none | The bundler plugin is done |
## Build pipeline
These come from the pipeline, so `.build()` and `.safeBuild()` fire them too.
| Hook | Payload | When it fires |
| ------------------------ | ------------------------------------------------------------- | ------------------------------------------------------ |
| `kubb:plugin:setup` | `KubbPluginSetupContext` | Once per plugin during setup, to register generators, resolvers, macros, and options |
| `kubb:build:start` | `{ config, adapter, meta, getPlugin, files, upsertFile }` | The AST is ready, before plugins run. Skipped when no adapter parsed input |
| `kubb:plugin:start` | `{ plugin }` | Before a plugin's generators run |
| `kubb:generate:schema` | `(node, ctx)` | For each schema node the adapter produced |
| `kubb:generate:operation`| `(node, ctx)` | For each operation node |
| `kubb:generate:operations`| `(nodes, ctx)` | Once with every operation node |
| `kubb:plugin:end` | `{ plugin, duration, success, error, config, files, upsertFile }` | After a plugin finishes, with its timing and a file snapshot |
| `kubb:plugins:end` | `{ config, files, upsertFile }` | After every plugin has generated, before files hit disk. The spot to add aggregate files like a barrel |
| `kubb:files:processing:start` | `{ files }` | Before the batch of generated files is written |
| `kubb:files:processing:update`| `{ files }` | As files are written. Here `files` holds progress records (`{ processed, total, percentage, source?, file, config }`), not the `FileNode` array the `:start` and `:end` variants carry |
| `kubb:files:processing:end` | `{ files }` | After the batch is written |
| `kubb:build:end` | `{ files, config, outputDir }` | After every file is written |
## Output passes
These run after a successful build, only during a full generation run.
| Hook | Payload | When it fires |
| -------------------- | ------------------------------------ | ------------------------------------------------ |
| `kubb:format:start` | none | Before the formatter runs |
| `kubb:format:end` | none | After formatting |
| `kubb:lint:start` | none | Before the linter runs |
| `kubb:lint:end` | none | After linting |
| `kubb:hooks:start` | none | Before the `postGenerate` commands run |
| `kubb:hook:start` | `{ id, command, name, args }` | Before one `postGenerate` command runs |
| `kubb:hook:line` | `KubbHookLineContext` | For each output line a `postGenerate` command emits |
| `kubb:hook:end` | `KubbHookEndContext` | After one `postGenerate` command finishes |
| `kubb:hooks:end` | none | After every `postGenerate` command |
## Messaging
These carry log messages and diagnostics, and can fire at any point.
| Hook | Payload | When it fires |
| ----------------- | --------------------------- | ---------------------------------------------------- |
| `kubb:info` | `{ message, info }` | An informational message |
| `kubb:success` | `{ message, info }` | A step completed successfully |
| `kubb:warn` | `{ message, info }` | A non-fatal problem |
| `kubb:error` | `{ error, meta }` | An unstructured error, so its stack survives |
| `kubb:diagnostic` | `{ diagnostic }` | A structured [diagnostic](../diagnostics) (warning, info, or an update notice) |
## Related
- [Plugins](./plugins) for the plugin `hooks` map and `KubbPluginSetupContext`
- [Engine](./engine) for `createKubb`, `.build()`, `.safeBuild()`, and `.generate()`
- [Plugin concepts](/docs/5.x/explanation/extensions#plugins) for the lifecycle as prose
- [Diagnostics](../diagnostics) for the shape of `kubb:diagnostic` payloads
---
- **Page:** Plugins · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/kit/plugins
- **Description:** defineExtension with kind plugin defines a Kubb plugin from one object with meta, dependencies, and a setup function that returns the resolved options, plus the KubbPluginSetupContext that registers generators, resolvers, and macros.
# Plugins
Plugins are the main extension point in Kubb. A plugin owns its file naming, its output folder, its lifecycle hooks, and the [generators](./generators) that walk the [AST](/docs/5.x/explanation/architecture#ast) and emit `FileNode` objects.
## `defineExtension`
`defineExtension` with `kind: 'plugin'` takes a definition object and returns a factory. Call it with the user's options to get a `Plugin`. Kubb runs `setup` before the plugin's generators, and the value `setup` returns becomes the plugin's resolved options.
```typescript twoslash [plugin-example.ts]
import { defineExtension, type PluginType } from 'kubb/kit'
type PluginExample = PluginType<'plugin-example', { prefix?: string }, { prefix: string }>
export const pluginExample = defineExtension({
kind: 'plugin',
meta: { name: 'plugin-example', version: '1.0.0' },
dependencies: { 'plugin-ts': {} },
setup(options, kubb) {
// Register resolvers, generators, and macros on `kubb`.
return { prefix: options.prefix ?? '' }
},
})
```
`PluginType` types the plugin. `TOptions` is what users pass, and `TResolvedOptions` is what `setup` returns and generators read. `meta` and `dependencies` are shared with parsers and described in [Extensions](./extensions).
### Definition shape
| Property | Type | Required | Description |
| -------------- | ------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `kind` | `'plugin'` | Yes | Tells `defineExtension` to define a plugin. |
| `meta` | [`ExtensionMeta`](./extensions#meta) | Yes | Name, version, and compatibility. `meta.name` follows `plugin-`. The plugin's own `name` is deprecated in favor of it, and optional when `meta.name` is set. |
| `setup` | `(options, kubb: KubbPluginSetupContext) => TResolvedOptions` | No | Main plugin logic. Receives the user's options and returns the resolved options. Can be `async`. |
| `dependencies` | [`ExtensionDependencies`](./extensions#dependencies) | No | Plugins this one builds on. They run first, and a missing required one fails the run. |
| `enforce` | `'pre' \| 'post'` | No | Run this plugin before (`'pre'`) or after (`'post'`) the normal plugins. Dependency order still wins. |
| `hooks` | `{ 'kubb:plugin:setup'?: ...; ... }` | No | Lifecycle handlers (see [Plugin API](/docs/5.x/explanation/extensions#plugins)). `kubb:plugin:setup` runs after `setup`. |
The `Plugin` the factory returns keeps the user's raw options in `plugin.options`.
### Read `compatibility` from the manifest
A published plugin ships a [`kubb-extension.json`](./manifest) with its `compatibility` ranges. Import only that field into `meta`, so Kubb checks the same ranges at runtime and a bundler leaves the rest of the manifest out of the build:
```typescript [src/plugin.ts]
import { defineExtension } from 'kubb/kit'
import { compatibility } from '../kubb-extension.json'
import { version } from '../package.json'
export const pluginExample = defineExtension({
kind: 'plugin',
meta: { name: 'plugin-example', version, compatibility },
})
```
Named imports from JSON need a bundler that inlines them. See [Extension manifest](./manifest#import-compatibility-into-meta).
### `definePlugin` (deprecated)
> [!WARNING]
> `definePlugin` is deprecated. Use `defineExtension` with `kind: 'plugin'` instead.
`definePlugin` takes the same definition object as `defineExtension`, without `kind`. To move over, rename the call and add `kind: 'plugin'`. See [Extensions](./extensions#define-extension).
## Setup context {#setup-context}
`setup` and `kubb:plugin:setup` register generators, the resolver, macros, and options through the setup context. A plugin reaches it in one of two ways:
- **The context argument**: `kubb` in `setup`, and `ctx` in the `kubb:plugin:setup` hook.
- **Composables** from `kubb/kit`, such as `addGenerator()`. They take no context argument, so helper functions that setup calls can use them too.
::::code-group
```typescript twoslash [kubb argument]
import { createResolver, defineExtension, defineGenerator } from 'kubb/kit'
const resolver = createResolver({ pluginName: 'plugin-example' })
const generator = defineGenerator({ name: 'example', operation: () => [] })
export const pluginExample = defineExtension({
kind: 'plugin',
meta: { name: 'plugin-example' },
setup(options, kubb) {
kubb.requirePlugin('plugin-ts')
kubb.setResolver(resolver)
kubb.addGenerator(generator)
return options
},
})
```
```typescript twoslash [Composables]
import { addGenerator, createResolver, defineExtension, defineGenerator, requirePlugin, setResolver } from 'kubb/kit'
const resolver = createResolver({ pluginName: 'plugin-example' })
const generator = defineGenerator({ name: 'example', operation: () => [] })
export const pluginExample = defineExtension({
kind: 'plugin',
meta: { name: 'plugin-example' },
setup(options) {
requirePlugin('plugin-ts')
setResolver(resolver)
addGenerator(generator)
return options
},
})
```
::::
| `kubb` member | Composable | Signature | Purpose |
| --------------- | ----------------- | --------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `addGenerator` | `addGenerator()` | `(...generators: Array) => void` | Register one or more generators for this plugin |
| `setResolver` | `setResolver()` | `(resolver: ResolverPatch \| Resolver) => void` | Set or partially override the file naming resolver |
| `addMacro` | `addMacro()` | `(macro: Macro) => void` | Add a macro that rewrites AST nodes before generators |
| `setMacros` | `setMacros()` | `(macros: Array) => void` | Replace this plugin's macros with a new list |
| `setOptions` | `setOptions()` | `(options: ResolvedOptions) => void` | Set the resolved options used by generators. In `setup`, return them instead. |
| `injectFile` | `injectFile()` | `(file: UserFileNode) => void` | Inject a raw file into the build output, bypassing generation |
| `requirePlugin` | `requirePlugin()` | `(name: string) => Plugin` | Return another plugin, or fail the run with `KUBB_PLUGIN_NOT_FOUND` |
| `config` | `useConfig()` | `Config` | The resolved build configuration at setup time |
| `options` | `useOptions()` | `TOptions` | The plugin's own options as passed by the user |
`useKubb()` returns the whole setup context. `tryUseKubb()` does the same, but returns `undefined` outside setup instead of throwing.
Composables read the context of the plugin whose setup is running, also after an `await`. Each plugin gets its own context, so composables in one plugin's setup never reach another plugin. Outside `setup` and `kubb:plugin:setup`, they throw [`KUBB_NO_CONTEXT`](/docs/5.x/reference/diagnostics#kubb-no-context). That includes generators and later hooks, which run after setup and receive their own `ctx`. Both ways can be used in the same setup.
> [!IMPORTANT]
> Plugin names follow the convention `plugin-`, such as `plugin-react-query` or `plugin-zod`.
---
- **Page:** Parsers · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/kit/parsers
- **Description:** defineExtension with kind parser defines a parser from one object with meta and a build function. A parser converts a generated file AST into the source string written to disk. Covers the Parser interface and adding your own.
# Parsers
A parser turns a `FileNode` into source code.
> [!TIP]
> For TypeScript and JavaScript output use the built-in [`@kubb/parser-ts`](/extensions/kubb-labs/parser-ts). It is added by default when you import `defineConfig` from the `kubb` package. Build a custom parser only when you target a different language, such as Python, Kotlin, or Rust.
## `defineExtension`
`defineExtension` with `kind: 'parser'` takes a definition object and returns a factory. `build` receives the caller's options, or an empty object when omitted, and returns the parser methods. Declare extensions with `extNames`:
```typescript twoslash [parserText.ts]
import { defineExtension } from 'kubb/kit'
export const parserText = defineExtension({
kind: 'parser',
meta: { name: 'text', version: '1.0.0' },
build() {
return {
extNames: ['.txt'],
parse(file) {
return file.sources
.flatMap((source) => source.nodes ?? [])
.map((node) => (node.kind === 'Text' ? node.value : ''))
.join('\n')
},
print(...nodes) {
return nodes.map(String).join('\n')
},
}
},
})
```
The parser's `name` comes from `meta.name`. Kubb checks `meta.compatibility` before the build, the same way it does for plugins. See [Extensions](./extensions).
### `defineParser` (deprecated)
> [!WARNING]
> `defineParser` is deprecated. Use `defineExtension` with `kind: 'parser'` instead.
`defineParser` takes the same definition object as `defineExtension`, without `kind`. To move over, rename the call and add `kind: 'parser'`. See [Extensions](./extensions#define-extension).
Wire it into your config:
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { parserTs, parserTsx } from '@kubb/parser-ts'
import { parserText } from './parserText.ts'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
parsers: [parserTs(), parserTsx(), parserText()],
})
```
## Parser anatomy
Every parser the factory returns matches the `Parser` interface from [`kubb/kit`](/docs/5.x/reference/kit). `build` returns every field except `name` and `meta`:
| Property | Type | Required | When called | Purpose |
| ---------- | -------------------------------------------------- | -------- | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | `string` | Yes | | Unique parser identifier, filled from `meta.name`. Use the output language or format, such as `'typescript'`. |
| `extNames` | `Array \| undefined` | Yes | | File extensions this parser handles. Set to `undefined` to register a catch-all fallback. |
| `parse` | `(file: FileNode) => string` | Yes | After all plugins run | Serializes the file's sources into the final output string. Must return synchronously. |
| `print` | `(...nodes: TNode[]) => string` | Yes | By plugins, while they generate files | Renders compiler AST nodes to source text. The node type is parser-specific, for example `ts.Node` for `parserTs`. |
| `copy` | `(file: FileNode, source: string) => UserFileNode` | No | For each `copy` file | Describes a copied template's raw content as nodes, for example its imports as `ImportNode`s, in the same shape `injectFile` takes. Kubb prints the result with `parse`. Omit it to write copied files verbatim. |
> [!IMPORTANT]
> If two parsers register the same extension, the last one in the `parsers` array wins. Order matters.
When no parser matches a file's extension, Kubb writes the file's source strings joined together.
## Parser naming convention
Parsers share the layout of [plugins](/docs/5.x/explanation/extensions#plugins) and [adapters](/docs/5.x/explanation/architecture#adapters):
| Surface | Pattern | Example |
| ------------------- | ------------------------------------------------ | ---------------------------- |
| npm package | `@/parser-` or `kubb-parser-` | `@kubb/parser-ts` |
| Parser runtime name | The output language or format (lowercase) | `'typescript'`, `'markdown'` |
| Factory export | `parser` (camelCase) | `parserTs`, `parserMd` |
Call the parser factory when registering it in `parsers`.
Parsers compose by extension. `parserTs` (`.ts`, `.js`) and `parserTsx` (`.tsx`, `.jsx`) ship in the same [`@kubb/parser-ts`](/extensions/kubb-labs/parser-ts) package and register side by side.
---
- **Page:** Testing · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/kit/testing
- **Description:** kubb/kit/testing is a separate subpath for the Vitest-backed helpers used to test plugins, generators, and adapters, kept apart from kubb/kit so the authoring toolkit never pulls in Vitest.
# Testing
`kubb/kit/testing` is a separate subpath for the Vitest-backed helpers used to test plugins, generators, and adapters. It stays separate from `kubb/kit` so importing the authoring toolkit never pulls Vitest into a plugin's runtime dependencies.
```typescript twoslash [plugin.test.ts]
import { createMockedPlugin, renderGeneratorOperation, matchFiles } from 'kubb/kit/testing'
```
The subpath exports mocking builders, generator runners, and a snapshot matcher:
| Export | What it does |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `createMockedPlugin` | Builds a minimal plugin for a test without wiring a full config. |
| `createMockedAdapter` | Builds a minimal adapter for a test without wiring a full config. `parse` returns an empty `InputNode` by default. |
| `createMockedPluginDriver` | Builds a driver around a set of plugins so a generator runs through its real lifecycle in isolation. |
| `createMockedSetupContext` | Builds the `kubb:plugin:setup` context with spy methods. Its `requirePlugin` fails for plugins not listed in `plugins`. |
| `renderGeneratorSchema` | Calls a generator's `schema()` method against a `SchemaNode` fixture and collects the files it emits. |
| `renderGeneratorOperation` | Calls a generator's `operation()` method against an `OperationNode` fixture and collects the files it emits. |
| `renderGeneratorOperations` | Calls a generator's `operations()` method against an array of `OperationNode` fixtures and collects the files it emits. |
| `matchFiles` | Asserts the generated `FileNode`s match expected paths and contents through file snapshots, the assertion most generator tests end on. |
## Test a plugin's setup {#plugin-setup}
Pass a mocked setup context to the plugin's `kubb:plugin:setup` handler, then assert on its spies. When setup uses [composables](/docs/5.x/reference/kit/plugins#setup-context), run it inside `kubbContext.run(ctx, …)`. Without it, the composables throw `KUBB_NO_CONTEXT`.
```typescript twoslash [plugin.test.ts]
import { addGenerator, defineExtension, kubbContext } from 'kubb/kit'
import { createMockedSetupContext } from 'kubb/kit/testing'
import { expect, test } from 'vitest'
const pluginExample = defineExtension({
kind: 'plugin',
meta: { name: 'plugin-example' },
hooks: {
'kubb:plugin:setup'() {
addGenerator({ name: 'example', operation: () => [] })
},
},
})
test('registers one generator', () => {
const plugin = pluginExample()
const ctx = createMockedSetupContext()
kubbContext.run(ctx, () => plugin.hooks['kubb:plugin:setup']?.(ctx))
expect(ctx.addGenerator).toHaveBeenCalledTimes(1)
})
```
---
- **Page:** Options · OpenAPI · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/adapter-oas/options
- **Description:** Configuration options for @kubb/adapter-oas.
# Options
Pass these options to `adapterOas()`. All of them are optional.
## Options overview
| Option | Purpose |
| ------------------------------------- | ------------------------------------------------------------ |
| [`validate`](#validate) | Validate the spec before parsing. |
| [`contentType`](#contenttype) | Preferred media type for request and response schemas. |
| [`server`](#server) | Which spec server Kubb resolves into the document `baseURL`. |
| [`discriminator`](#discriminator) | How `discriminator` fields are interpreted. |
| [`enums`](#enums) | Where inline enums live. |
| [`dateType`](#datetype) | How `date-time`, `date`, and `time` schemas are represented. |
| [`integerType`](#integertype) | How `int64` and `uint64` integers map to TypeScript. |
| [`unknownType`](#unknowntype) | Type for schemas Kubb cannot infer. |
| [`emptySchemaType`](#emptyschematype) | Type for empty schemas. |
| [`enumSuffix`](#enumsuffix) | Suffix for derived enum names. |
## Option details
### validate
Validates the OpenAPI spec with `@readme/openapi-parser` before parsing. Each problem is reported as a [`KUBB_INVALID_SPEC`](https://kubb.dev/docs/5.x/reference/diagnostics#kubb-invalid-spec) warning, and generation continues. Set it to `false` to skip the check, which makes generation faster on a large spec. Run [`kubb validate`](https://kubb.dev/docs/5.x/reference/commands/validate) to list every error.
| | |
| -------- | --------- |
| Type | `boolean` |
| Required | `false` |
| Default | `true` |
### contentType
Media type to keep when an operation declares several, for both request bodies and responses. Without a value, Kubb keeps every media type the operation declares.
| | |
| -------- | ------------------------------ |
| Type | `'application/json' \| string` |
| Required | `false` |
### server
Selects which entry in the spec's `servers` array Kubb resolves into the document `baseURL`, filling in any `{variable}` placeholders. `server.index` points at one of the spec's servers, usually `0` for the primary one. `server.variables` supplies placeholder values, falling back to each variable's `default` from the spec. Omit `server` and `baseURL` resolves to `null`.
| | |
| -------- | -------------------------------------------------------- |
| Type | `{ index?: number, variables?: Record }` |
| Required | `false` |
The resolved `baseURL` reaches banner functions through `BannerMeta.baseURL` but does not set request URLs on its own. To change where a generated client sends requests, use that plugin's own `baseURL` option ([`@kubb/plugin-fetch`](https://kubb.dev/extensions/kubb-labs/plugin-fetch), [`@kubb/plugin-axios`](https://kubb.dev/extensions/kubb-labs/plugin-axios), [`@kubb/plugin-msw`](https://kubb.dev/extensions/kubb-labs/plugin-msw)).
With a spec server of `https://api.{env}.example.com`, `server: { index: 0, variables: { env: 'prod' } }` resolves `baseURL` to `https://api.prod.example.com`.
### discriminator
How `discriminator` fields on `oneOf`/`anyOf` schemas are interpreted.
| | |
| -------- | --------------------------- |
| Type | `'preserve' \| 'propagate'` |
| Required | `false` |
| Default | `'preserve'` |
::field-group
:::field{name="'preserve'"}
Keeps child schemas exactly as written, though the discriminator still narrows types at the call site.
:::
:::field{name="'propagate'"}
Pushes the discriminator property with its literal value into each child schema, so each branch's `type` field is precisely typed.
:::
::
::code-group
```yaml [OpenAPI spec]
openapi: 3.0.3
components:
schemas:
Animal:
required: [type]
type: object
oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
discriminator:
propertyName: type
mapping:
cat: '#/components/schemas/Cat'
dog: '#/components/schemas/Dog'
Cat:
type: object
properties:
type: { type: string }
indoor: { type: boolean }
Dog:
type: object
properties:
type: { type: string }
name: { type: string }
```
```typescript ['preserve' (default)]
export type Cat = { type: string; indoor?: boolean }
export type Dog = { type: string; name?: string }
export type Animal = Cat | Dog
```
```typescript ['propagate']
export type Cat = { type: 'cat'; indoor?: boolean }
export type Dog = { type: 'dog'; name?: string }
export type Animal = Cat | Dog
```
::
### enums
Where inline enums live.
| | |
| -------- | -------------------- |
| Type | `'inline' \| 'root'` |
| Required | `false` |
| Default | `'inline'` |
::field-group
:::field{name="'inline'"}
Keeps each enum on the property that declares it.
:::
:::field{name="'root'"}
Lifts every inline enum to a reusable top-level schema named after its context (for example `PetStatusEnum`) and references it wherever it appears.
:::
::
For an enum with values `active` and `inactive` on `Pet.status`:
::code-group
```typescript ['inline' (default)]
export type Pet = { status?: 'active' | 'inactive' }
```
```typescript ['root']
export type PetStatusEnum = 'active' | 'inactive'
export type Pet = { status?: PetStatusEnum }
```
::
### dateType
How `date-time`, `date`, and `time` schemas are represented downstream.
| | |
| -------- | ----------------------------------------------------------------------------------------------- |
| Type | `false \| 'string' \| 'stringOffset' \| 'stringLocal' \| 'date' \| { dateTime?, date?, time? }` |
| Required | `false` |
| Default | `'string'` |
Pass a single value to apply it to all three formats:
::field-group
:::field{name="false"}
Represents date and time values as plain strings without format validation.
:::
:::field{name="'string'"}
Represents `date-time`, `date`, and `time` as ISO 8601 strings. The generated TypeScript type is `string`.
:::
:::field{name="'stringOffset'"}
Represents `date-time` as a string with a timezone offset. The `date` and `time` formats fall back to `'string'`.
:::
:::field{name="'stringLocal'"}
Represents `date-time` as a local string without a timezone. The `date` and `time` formats fall back to `'string'`.
:::
:::field{name="'date'"}
Represents date and time values as JavaScript `Date` objects. JSON values need parsing to revive them as `Date` objects.
:::
::
The string variants all emit `string` at the TypeScript type level. Schema plugins such as `@kubb/plugin-zod` validate the offset or local format.
Pass an object to set `dateTime`, `date`, and `time` independently. A key you leave out defaults to `'string'`, regardless of the other keys.
```ts
adapterOas({
dateType: {
dateTime: 'date', // Date object for timestamps
date: 'string',
time: 'string',
},
})
```
### integerType
How a schema with `format: int64` or `format: uint64` maps to TypeScript. Other integers, such as `type: integer` without a format or with `format: int32`, always map to `number`.
| | |
| -------- | ---------------------- |
| Type | `'number' \| 'bigint'` |
| Required | `false` |
| Default | `'bigint'` |
::field-group
:::field{name="'bigint'"}
Represents 64-bit IDs exactly, but `JSON.stringify` and `JSON.parse` cannot round-trip it. Use it only when you handle bigint serialization yourself.
:::
:::field{name="'number'"}
Fits most JSON APIs. It loses precision above `Number.MAX_SAFE_INTEGER`.
:::
::
A schema with `type: string` stays a `string` whatever its `format`, so the [ProtoJSON](https://protobuf.dev/programming-guides/json/#int64-strings) `int64` strings that gRPC-gateway emits stay strings. `@kubb/plugin-zod` validates them with a digits regex, and `@kubb/plugin-faker` mocks them as numeric strings.
### unknownType
AST type used when a schema's type cannot be inferred from the spec (`additionalProperties: true`, a missing `type`, and similar).
| | |
| -------- | ------------------------------ |
| Type | `'any' \| 'unknown' \| 'void'` |
| Required | `false` |
| Default | `'unknown'` |
::field-group
:::field{name="'unknown'"}
Requires callers to narrow the value before using it.
:::
:::field{name="'any'"}
Allows callers to use the value without type checking.
:::
:::field{name="'void'"}
Represents a value callers should not use. Choose it when matching a legacy API that uses `void`.
:::
::
### emptySchemaType
AST type used for empty schemas (`{}`). It takes the same values as [`unknownType`](#unknowntype) and follows it unless you set it.
| | |
| -------- | -------------------------------------- |
| Type | `'any' \| 'unknown' \| 'void'` |
| Required | `false` |
| Default | `unknownType` (`'unknown'` by default) |
> [!TIP]
> A common pairing sets `unknownType: 'unknown'` for safety and `emptySchemaType: 'any'` so empty 204 response bodies stay easy to use.
### enumSuffix
Suffix for the names Kubb gives inline enums: schema name, property name, and suffix, in PascalCase. The `status` enum on `Pet` becomes `PetStatusEnum`, or `PetStatusType` with `enumSuffix: 'type'`.
| | |
| -------- | -------- |
| Type | `string` |
| Required | `false` |
| Default | `'enum'` |
---
- **Page:** OpenAPI · @kubb/adapter-oas · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/adapter-oas
- **Description:** Reads an OpenAPI 2.0, 3.0, or 3.1 spec and converts every schema and operation into the AST that Kubb plugins generate from.
# OpenAPI
The OpenAPI adapter is the first step of every build. It converts your spec into Kubb's AST, and every plugin generates code from that AST, so the adapter's options apply to all of them.
The adapter downloads a remote `input` URL and any remote `$ref`s with a plain GET request, without credentials. It also reads the local files that external `$ref`s point to, even outside the spec's folder, and never writes files.
## Installation
::code-group{sync="package-manager"}
```shell [bun]
bun add -d @kubb/adapter-oas
```
```shell [pnpm]
pnpm add -D @kubb/adapter-oas
```
```shell [npm]
npm install --save-dev @kubb/adapter-oas
```
```shell [yarn]
yarn add -D @kubb/adapter-oas
```
::
Or run `kubb add adapter-oas` to install the version the [Kubb registry](/registry) pins and add `adapterOas()` to `kubb.config.ts`.
## Setup
Kubb uses `adapterOas()` by default, so no setup is needed. Set `adapter` in `defineConfig` only to change its options.
## Options worth knowing
- `validate` checks the spec before parsing and reports each problem as a warning. Turn it off to speed up a large spec. Run `kubb validate` to list every error.
- `dateType` sets how `date-time`, `date`, and `time` schemas are typed. Choose ISO strings (the default), `date-time` strings with or without a timezone offset, or JavaScript `Date` objects. Pass an object to set each format on its own.
- `integerType` sets how `int64` and `uint64` schemas are typed. The default `'bigint'` is exact for 64-bit IDs but does not survive `JSON.stringify`. Choose `'number'` for most JSON APIs.
- `unknownType` and `emptySchemaType` set the type for schemas Kubb cannot infer and for empty schemas (`{}`).
- `discriminator: 'propagate'` writes the discriminator's literal value into each child schema, so each branch is typed precisely.
- `enums: 'root'` lifts inline enums to reusable top-level schemas, named with `enumSuffix` (`PetStatusEnum`).
- `server` picks the entry in the spec's `servers` array that becomes the base URL and fills in its variables. It does not change where a generated client sends requests. Use the client plugin's own `baseURL` for that.
- `contentType` picks one media type when an operation declares several. Without it, Kubb keeps every media type the operation declares.
See [Options](https://kubb.dev/extensions/kubb-labs/adapter-oas/options) for every option and its default.
## Example
The config below types dates as `Date` objects and 64-bit integers as numbers.
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { adapterOas } from '@kubb/adapter-oas'
import { pluginTs } from '@kubb/plugin-ts'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
adapter: adapterOas({ dateType: 'date', integerType: 'number' }),
plugins: [
pluginTs(),
],
})
```
---
- **Page:** Barrel · @kubb/plugin-barrel · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-barrel
- **Description:** Generates index.ts barrel files for every plugin output, plus a root barrel when output.barrel is set on defineConfig.
# Barrel
The Barrel plugin writes `index.ts` files that re-export generated code, so you can import everything from a single entry point. It writes a barrel in every folder of each plugin output that has a barrel setting, plus a root barrel when you set `output.barrel` on `defineConfig`.
## Installation
::code-group{sync="package-manager"}
```shell [bun]
bun add -d @kubb/plugin-barrel
```
```shell [pnpm]
pnpm add -D @kubb/plugin-barrel
```
```shell [npm]
npm install --save-dev @kubb/plugin-barrel
```
```shell [yarn]
yarn add -D @kubb/plugin-barrel
```
::
Or run `kubb add plugin-barrel` to install the version the [Kubb registry](/registry) pins and add `pluginBarrel()` to `kubb.config.ts`.
## Setup
Kubb adds the plugin to `plugins` for you, so no setup is needed. Generator plugins such as `pluginTs()` turn on their own barrels by default. Plugins without their own `output.barrel` inherit the root setting.
## Options worth knowing
`pluginBarrel()` takes no arguments. You configure it through `output.barrel`, on `defineConfig` or on a single plugin.
- `type: 'named'` re-exports each symbol by name, which suits tree-shaking. `type: 'all'` writes `export *`.
- `nested: true`, on a plugin only, makes each barrel re-export just its own folder and the barrels below it. The root barrel is always flat.
- `false` on a plugin turns its barrel off and leaves its files out of the root barrel.
A plugin with `output.mode: 'file'` gets no barrel of its own, and the root barrel re-exports that file directly. Passing your own `output` object to a plugin replaces its default `barrel: { type: 'named' }`, so that plugin falls back to the root setting. When two files export the same name, Kubb reports an error, and a `named` barrel keeps only the first one.
See [Options](https://kubb.dev/extensions/kubb-labs/plugin-barrel/options) for every option and its default.
## Example
The config below writes a root `src/gen/index.ts` that re-exports the generated types by name.
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { pluginTs } from '@kubb/plugin-ts'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen', barrel: { type: 'named' } },
plugins: [
pluginTs(),
],
})
```
---
- **Page:** Options · TypeScript · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/parser-ts/options
- **Description:** Configuration options for @kubb/parser-ts.
# Options
`parserTs` and `parserTsx` accept the same single option, `extension`, which rewrites the import and export extensions the TypeScript parser emits.
## Options overview
| Option | Purpose | Default |
| ------------------------- | --------------------------------------------------------------- | --------------- |
| [`extension`](#extension) | Rewrite the extensions emitted in `import`/`export` statements. | `{ '.ts': '' }` |
## Option details
### extension
Rewrites the extensions emitted in relative `import`/`export` statements. Each key is the extension of a generated file, and its value is the extension written on the relative specifiers in that file. `''` drops it, and so does a generated file whose extension has no key. Package specifiers and the on-disk filenames never change.
Use `{ '.ts': '.js' }` to emit `.js` specifiers for ESM output compiled to JavaScript. Use `{ '.ts': '.ts' }` to keep `.ts` specifiers when you run the `.ts` files directly in Node.js or compile them with `rewriteRelativeImportExtensions`.
The same mapping applies to runtime templates a plugin copies into the output, such as the `.kubb/` runtime files of `@kubb/plugin-fetch`. Their top-level `import` and `export … from` statements become import and export nodes, so the whole output follows one convention.
| | |
| -------- | ------------------------ |
| Type | `Record` |
| Required | `false` |
| Default | `{ '.ts': '' }` |
```typescript
parserTs({ extension: { '.ts': '.js' } }) // import './api.js' instead of './api'
parserTs({ extension: { '.ts': '.ts' } }) // import './api.ts' instead of './api'
```
---
- **Page:** TypeScript · @kubb/parser-ts · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/parser-ts
- **Description:** Prints the Kubb AST as TypeScript source and rewrites the extensions of relative imports and exports.
# TypeScript
The TypeScript parser writes `.ts` and `.js` files. It turns each file's AST into source text with imports, exports, declarations, and JSDoc, and resolves relative import paths. Plugins such as `@kubb/plugin-ts` print TypeScript nodes with its `print` helper, which uses the official TypeScript printer.
The package also exports `parserTsx`, which writes `.tsx` and `.jsx` files with the same options.
## Installation
::code-group{sync="package-manager"}
```shell [bun]
bun add -d @kubb/parser-ts
```
```shell [pnpm]
pnpm add -D @kubb/parser-ts
```
```shell [npm]
npm install --save-dev @kubb/parser-ts
```
```shell [yarn]
yarn add -D @kubb/parser-ts
```
::
Or run `kubb add parser-ts` to install the version the [Kubb registry](/registry) pins and add `parserTs()` to `kubb.config.ts`.
## Setup
With `defineConfig` from `kubb/config`, Kubb registers `parserTs`, `parserTsx`, and `parserMd` by default, so no setup is needed. Bundler integrations register only `parserTs` and `parserTsx`. Set `parsers` in `defineConfig` only to change an option or add a parser. A custom `parsers` array replaces the default set, so list every parser your plugins need. Files that no parser claims are written as their source text only, without imports, exports, banner, or footer.
## Options worth knowing
- `extension` rewrites the extension of relative imports and exports. Each key is a generated file's extension, and each value is the extension its relative imports and exports get. `''` drops it. By default, imports in `.ts` files have no extension. Use `{ '.ts': '.js' }` for ESM packages. Use `{ '.ts': '.ts' }` when Node.js runs the `.ts` files directly, or when you compile with `rewriteRelativeImportExtensions`. Package imports stay unchanged.
`parserTsx` reads its own `extension` map, so set the `.tsx` key on it as well.
See [Options](https://kubb.dev/extensions/kubb-labs/parser-ts/options) for its type and default.
## Example
The config below adds `.js` to relative imports in `.ts` and `.tsx` files and keeps every default parser registered.
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { parserMd } from '@kubb/parser-md'
import { parserTs, parserTsx } from '@kubb/parser-ts'
import { pluginTs } from '@kubb/plugin-ts'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
parsers: [
parserTs({ extension: { '.ts': '.js' } }),
parserTsx({ extension: { '.tsx': '.js' } }),
parserMd(),
],
plugins: [
pluginTs(),
],
})
```
---
- **Page:** Markdown · @kubb/parser-md · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/parser-md
- **Description:** Writes .md and .markdown files from the Kubb AST, with YAML frontmatter from a file's meta.
# Markdown
The Markdown parser joins a file's source blocks as plain Markdown, separated by blank lines. When a file sets `meta.frontmatter`, the parser writes that object as YAML frontmatter above the content, after the file banner if one is set.
## Installation
::code-group{sync="package-manager"}
```shell [bun]
bun add -d @kubb/parser-md
```
```shell [pnpm]
pnpm add -D @kubb/parser-md
```
```shell [npm]
npm install --save-dev @kubb/parser-md
```
```shell [yarn]
yarn add -D @kubb/parser-md
```
::
Or run `kubb add parser-md` to install the version the [Kubb registry](/registry) pins and add `parserMd()` to `kubb.config.ts`.
## Setup
With `defineConfig` from `kubb/config`, Kubb registers the parser by default, next to `parserTs` and `parserTsx`, so no setup is needed. Bundler integrations leave it out. Add it yourself only when you set a custom `parsers` array, because that array replaces the default set. List every parser your plugins need. Files that no parser claims are written as their source text only, without imports, exports, banner, or footer.
## Options worth knowing
The parser takes no options. Plugins control the output through `meta.frontmatter` on each file, and an empty object writes none.
See [Options](https://kubb.dev/extensions/kubb-labs/parser-md/options) for how a plugin sets frontmatter.
## Example
The config below sets a custom `parsers` array and keeps the Markdown parser in it.
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { parserMd } from '@kubb/parser-md'
import { parserTs, parserTsx } from '@kubb/parser-ts'
import { pluginTs } from '@kubb/plugin-ts'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
parsers: [
parserTs(),
parserTsx(),
parserMd(),
],
plugins: [
pluginTs(),
],
})
```
---
- **Page:** Cypress · @kubb/plugin-cypress · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-cypress
- **Description:** Generates a typed cy.request() wrapper per OpenAPI operation so your Cypress tests call the API through generated helpers and catch broken calls at compile time.
# Cypress
The Cypress plugin generates a typed `cy.request()` helper for each operation in your OpenAPI spec.
Each helper takes grouped `path`, `query`, `headers`, and `body` parameters named after the spec. It returns the response body typed as `Cypress.Chainable<{Operation}Response>`.
## Installation
::code-group{sync="package-manager"}
```shell [bun]
bun add -d @kubb/plugin-cypress
```
```shell [pnpm]
pnpm add -D @kubb/plugin-cypress
```
```shell [npm]
npm install --save-dev @kubb/plugin-cypress
```
```shell [yarn]
yarn add -D @kubb/plugin-cypress
```
::
Or run `kubb add plugin-cypress` to install the version the [Kubb registry](/registry) pins and add `pluginCypress()` to `kubb.config.ts`.
## Setup
- Add `@kubb/plugin-ts` for the request and response types.
- Install `cypress` v15 or v16 in the project that runs the tests.
- Add `"types": ["cypress"]` to the tsconfig that covers the generated files, because the helpers use the global `Cypress` namespace.
## Options worth knowing
- `baseURL` is prepended to every request. Without it, Cypress resolves the path against its own `baseUrl`.
See [Options](https://kubb.dev/extensions/kubb-labs/plugin-cypress/options) for every option and its default.
## Example
The config below writes the helpers to `src/gen/cypress`.
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { pluginTs } from '@kubb/plugin-ts'
import { pluginCypress } from '@kubb/plugin-cypress'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
plugins: [
pluginTs(),
pluginCypress({ output: { path: 'cypress', mode: 'directory' } }),
],
})
```
A test then calls a helper and gets a typed response body. `petId` is an `int64`, which the default adapter types as `bigint`.
```typescript [cypress/e2e/pet.cy.ts]
import { getPetById } from '../../src/gen/cypress/getPetById'
describe('Pet API', () => {
it('returns the pet by id', () => {
getPetById({ path: { petId: 1n } }).then((pet) => {
expect(pet.name).to.be.a('string')
})
})
})
```
---
- **Page:** Options · Axios · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-axios/options
- **Description:** Configuration options for @kubb/plugin-axios.
# Options
Pass these options to `pluginAxios()`. Shared options link to [Shared plugin options](https://kubb.dev/docs/5.x/reference/plugin-options).
## Options overview
| Option | Purpose | Default |
| ------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------ |
| [`output`](https://kubb.dev/docs/5.x/reference/plugin-options#output) | Where files are written: `path`, `mode`, `barrel`, `banner`, `footer`. | `{ path: 'clients', barrel: { type: 'named' } }` |
| [`group`](https://kubb.dev/docs/5.x/reference/plugin-options#group) | Split output by tag or path: `type`, `name`. | None |
| [`baseURL`](#baseurl) | Base URL prepended to every request. | None |
| [`throwOnErrorDefault`](#throwonerrordefault) | Default error behavior and return type for generated operations. | `true` |
| [`validator`](#validator) | Validate request and response bodies with Zod. | `false` |
| [`sdk`](#sdk) | Emit a class-based SDK instead of standalone functions. | None |
| [`returnType`](#returntype) | Shape of the value a generated call resolves to. | `'full'` |
| [`include`](https://kubb.dev/docs/5.x/reference/plugin-options#include) | Keep only operations that match. | None |
| [`exclude`](https://kubb.dev/docs/5.x/reference/plugin-options#exclude) | Skip operations that match. | `[]` |
| [`override`](https://kubb.dev/docs/5.x/reference/plugin-options#override) | Apply different options per pattern. | `[]` |
| [`resolver`](#resolver) | Customize generated names and file paths. | `resolverClient` |
| [`macros`](https://kubb.dev/docs/5.x/reference/plugin-options#macros) | Rewrite AST nodes before printing. | `[]`, run after the built-in client macros |
## Option details
### baseURL
Base URL prepended to every request. When omitted, each request uses the operation's relative path from the spec, with no server-URL fallback. A value with a `${...}` interpolation is emitted as a template literal, so `baseURL: '${process.env.API_URL}'` reads the environment variable at runtime.
| | |
| -------- | -------- |
| Type | `string` |
| Required | `false` |
### throwOnErrorDefault
Set `throwOnErrorDefault: false` to return documented error responses as values by default. It sets the fallback on each generated request and the default `ThrowOnError` type parameter on functions and SDK methods. It applies to the whole plugin, so `override` cannot set it. A call that passes `throwOnError` still wins. With `throwOnError: true`, a non-2xx response throws and the return type narrows to successful responses. Query hooks always pass `throwOnError: true`.
| | |
| -------- | --------- |
| Type | `boolean` |
| Required | `false` |
| Default | `true` |
```typescript
// with pluginAxios({ throwOnErrorDefault: false })
const result = await getPetById({ path: { petId: 1 } })
if (result.status !== 200) console.error(result.status, result.error)
```
### validator
Validates request and response bodies with schemas from `@kubb/plugin-zod`, so add `pluginZod()` too. An invalid body makes the generated function throw a `ParseError`.
| | |
| -------- | --------------------------------------------------------- |
| Type | `false \| 'zod' \| { request?: 'zod'; response?: 'zod' }` |
| Required | `false` |
| Default | `false` |
::field-group
:::field{name="false"}
Default value. Skips validation and casts the response to the generated type.
:::
:::field{name="'zod'"}
Validates the success response body and, when a non-2xx call does not throw, the error body.
:::
:::field{name="{ request?: 'zod', response?: 'zod' }"}
Enables validation separately for requests and responses.
:::
::
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { pluginTs } from '@kubb/plugin-ts'
import { pluginZod } from '@kubb/plugin-zod'
import { pluginAxios } from '@kubb/plugin-axios'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
plugins: [
pluginTs(),
pluginZod(),
pluginAxios({ validator: { request: 'zod', response: 'zod' } }),
],
})
```
### sdk
Generates a class-based SDK. Each instance takes its own client config, so environments can use separate clients. Leave `sdk` unset to keep the standalone functions that query plugins call.
| | |
| -------- | ------------------------------------------- |
| Type | `{ mode?: 'tag' \| 'flat'; name?: string }` |
| Required | `false` |
::field-group
:::field{name="'tag'"}
Default value for `sdk.mode`. Generates one class per tag, such as `PetClient`. Set `sdk.name` to also get a root class that shares one config, used as `new PetStore(config).pet.getPetById(...)`.
:::
:::field{name="'flat'"}
Generates one class named by `sdk.name`, with every operation as a method. Supports single-file output.
:::
::
`mode: 'tag'` needs one file per tag, so it throws [`KUBB_INVALID_PLUGIN_OPTIONS`](https://kubb.dev/docs/5.x/reference/diagnostics#kubb-invalid-plugin-options) with single-file output. Use `mode: 'flat'` for a single file.
Methods take the same grouped options and return the same result as the standalone functions. See [Call operations](https://kubb.dev/extensions/kubb-labs/plugin-axios/guides/calling-operations).
```typescript
const pet = new PetClient({ baseURL: 'https://petstore.swagger.io/v2' })
const { data } = await pet.getPetById({ path: { petId: 1 } })
```
### returnType
Shape of the value a generated call resolves to.
| | |
| -------- | ------------------ |
| Type | `'full' \| 'data'` |
| Required | `false` |
| Default | `'full'` |
::field-group
:::field{name="'full'"}
Default value. Returns `{ status, data, error, contentType, request, response }`.
:::
:::field{name="'data'"}
Returns the success body when `throwOnError` is `true`. With `throwOnError: false`, returns the full result so callers can tell errors from successes.
:::
::
```typescript
pluginAxios({ returnType: 'data' })
const pet = await getPetById({ path: { petId: 1 } }) // Pet, not { status, data, ... }
```
It applies to the functions and the SDK. The query plugins and `@kubb/plugin-mcp` read it too, including a per-operation value set through [`override`](https://kubb.dev/docs/5.x/reference/plugin-options#override). To read headers such as `ETag` under `'data'`, pass `throwOnError: false` and read `result.response.headers`.
### resolver
Overrides generated file and symbol names. Omitted members keep `resolverClient`. The shared members (`name`, `file`, `imports`) and the `this` context are described under [`resolver`](https://kubb.dev/docs/5.x/reference/plugin-options#resolver).
| | |
| -------- | ------------------------------- |
| Type | `ResolverPatch` |
| Required | `false` |
```typescript [Partial override]
type ResolverClientPatch = {
name?(name: string): string
file?: {
baseName?(params: { name: string; extname: string }): string
path?(params: { baseName: string; output: Output }): string
}
imports?(options: ResolveImportsOptions): Array
className?(name: string): string
groupName?(name: string): string // → 'PetClient'
propertyName?(name: string): string
}
```
---
- **Page:** Resolvers · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/kit/resolvers
- **Description:** createResolver builds a Resolver that controls file naming and path resolution for a plugin, with auto-injected defaults under resolver.default and Resolver.merge for layering overrides.
# Resolvers
## `createResolver`
`createResolver` builds a plugin resolver for names, paths, and imports.
Provide `pluginName`. Methods use `this` to reach the merged resolver, so namespaced methods call `this.name(...)` for active casing.
```typescript twoslash [resolver.ts]
import { createResolver } from 'kubb/kit'
import type { PluginType, Resolver } from 'kubb/kit'
// Extend the base Resolver with plugin-specific naming namespaces.
type MyResolver = Resolver & {
schema: {
name(node: { name: string }): string
}
}
type MyPlugin = PluginType<'plugin-example', object, object, MyResolver>
export const resolver = createResolver({
pluginName: 'plugin-example',
name(name) {
return `${name.charAt(0).toUpperCase()}${name.slice(1)}`
},
schema: {
name(node) {
return this.name(node.name)
},
},
})
```
### Auto-injected resolver defaults
| Method | Default behavior |
| ---------------- | ---------------------------------------------------------------------- |
| `name` | Active top-level identifier casing. Delegates to `default.name` when omitted |
| `file` | Top-level `FileNode` builder, delegates to `default.file` |
| `default.name` | The core `camelCase` generated-identifier casing |
| `default.options`| Applies `exclude`, `include`, and `override` filters |
| `default.path` | Resolves to `output.path`, with optional tag/path-based subdirectories |
| `default.file` | Constructs a full `FileNode` using the resolver's `file.baseName` casing (camelCase by default, with `pet.petId` becoming `pet/petId`) |
| `default.banner` | Returns `output.banner` or the standard "Generated by Kubb" header |
| `default.footer` | Returns `output.footer` when set |
### `resolver.imports` {#imports}
`resolver.imports` builds one import entry per `$ref` in a schema tree, so a generator emits the imports for every schema the current node references. Each import uses the ref's `targetName` when set, and otherwise the last segment of its pointer.
The resulting names and paths go through the resolver's own `name` and `file` conventions. `extname` defaults to `.ts`.
```typescript twoslash [imports.ts]
import { ast } from 'kubb/kit'
import type { GeneratorContext, PluginType } from 'kubb/kit'
declare const ctx: GeneratorContext
const { resolver, root, output } = { ...ctx, output: { path: 'types' } }
const node = ast.factory.createSchema({ type: 'ref', ref: '#/components/schemas/Pet' })
// ---cut---
const imports = resolver.imports({ node, root, output })
// → [{ kind: 'Import', name: ['pet'], path: '/src/types/pet.ts' }]
```
Pass `name` to override how a referenced schema name becomes the imported identifier, for example to point enum refs at a suffixed type name:
```typescript twoslash [importsName.ts]
import { ast } from 'kubb/kit'
import type { GeneratorContext, PluginType } from 'kubb/kit'
declare const ctx: GeneratorContext
const { resolver, root, output } = { ...ctx, output: { path: 'types' } }
const node = ast.factory.createSchema({ type: 'ref', ref: '#/components/schemas/Pet' })
// ---cut---
const imports = resolver.imports({
node,
root,
output,
name: (schemaName) => `${resolver.name(schemaName)}Type`,
})
```
### `Resolver.merge`
`Resolver.merge(base, patch)` returns a new resolver with `patch`'s fields layered over `base`'s and every helper re-bound. A top-level `name` replaces, while `file` and each namespace merge per member, so overriding `query.name` keeps the base `query.keyName`.
Use it to compose resolvers or apply partial overrides.
> [!TIP]
> Type a patch with `ResolverPatch` to keep `this` and namespace shapes checked against the target resolver.
```typescript twoslash [merge.ts]
import { createResolver, Resolver } from 'kubb/kit'
import type { PluginType } from 'kubb/kit'
const resolver = createResolver({ pluginName: 'plugin-example' })
// ---cut---
const patched = Resolver.merge(resolver, {
name(name) {
return `Custom${this.default.name(name)}`
},
})
```
## Resolver overrides {#resolver-overrides}
`name` changes identifier casing. `file.baseName` and `file.path` control files. Plugin namespaces control specific symbols.
```typescript [Type definition]
type ResolverPatch = {
name?: (name: string) => string
file?: {
baseName?: (params: { name: string; extname: string }) => string
path?: (params: { baseName: string; output: Output }) => string
}
// plugin-specific namespaces, such as query.keyName or schema.typeName
}
```
Methods run with a `this` context bound to the full, merged resolver, so write them as regular functions rather than arrow functions. `this.default.name(name)` always applies Kubb's core `camelCase` default. The plugin preset's `name` method remains separate.
From a namespaced method, `this.name(name)` calls the active top-level `name` method and follows any user override. Calling `this.name` from the top-level `name` method itself recurses, so call an exported preset resolver such as `resolverTs.name` when you want to wrap its casing.
---
- **Page:** Faker · @kubb/plugin-faker · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-faker
- **Description:** Generates a Faker.js mock-data factory for every schema in your OpenAPI spec.
# Faker
The Faker plugin generates one factory function per schema. Each factory returns mock data from Faker.js and accepts partial data that overrides the generated values.
Use the factories in tests, Storybook, and local development without a running backend. `@kubb/plugin-msw` can use them to fill mock responses.
## Installation
::code-group{sync="package-manager"}
```shell [bun]
bun add -d @kubb/plugin-faker
```
```shell [pnpm]
pnpm add -D @kubb/plugin-faker
```
```shell [npm]
npm install --save-dev @kubb/plugin-faker
```
```shell [yarn]
yarn add -D @kubb/plugin-faker
```
::
Or run `kubb add plugin-faker` to install the version the [Kubb registry](/registry) pins and add `pluginFaker()` to `kubb.config.ts`.
## Setup
- Add `@kubb/plugin-ts` for the factory return types. Generation fails without it.
- Install `@faker-js/faker` v10 in the app that uses the generated code.
- Install `dayjs`, `moment`, or `randexp` when you pick it in `dateParser` or `regexGenerator`.
## Options worth knowing
- `seed` passes a fixed seed to `faker.seed(...)`, so every run returns the same data.
- `locale` sets the Faker locale. The default is `en`.
- `dateParser` formats `date` and `time` strings with `faker` (default), `dayjs`, or `moment`. `date-time` values always use Faker. `dayjs` and `moment` do not work when the adapter types a date or time as `Date`, for example with `dateType: 'date'`.
- `regexGenerator` turns a `pattern` into a string with `faker` (default) or `randexp`.
- `typeMode` sets the factory types: `inferred` (default) derives them from the generated values, and `schema` uses the declared model type.
See [Options](https://kubb.dev/extensions/kubb-labs/plugin-faker/options) for every option and its default.
## Example
The config below generates the factories with a fixed seed.
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { pluginTs } from '@kubb/plugin-ts'
import { pluginFaker } from '@kubb/plugin-faker'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
plugins: [
pluginTs(),
pluginFaker({ seed: [100] }),
],
})
```
---
- **Page:** Options · Client · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-client/options
- **Description:** Configuration options for @kubb/plugin-client.
# Options
Pass these options to `pluginClient()`. Shared options link to [Shared plugin options](https://kubb.dev/docs/5.x/reference/plugin-options).
## Options overview
| Option | Purpose | Default |
| ------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------ |
| [`importPath`](#importpath) | Import specifier of your client module. | Required |
| [`output`](https://kubb.dev/docs/5.x/reference/plugin-options#output) | Where files are written: `path`, `mode`, `barrel`, `banner`, `footer`. | `{ path: 'clients', barrel: { type: 'named' } }` |
| [`group`](https://kubb.dev/docs/5.x/reference/plugin-options#group) | Split output by tag or path: `type`, `name`. | None |
| [`throwOnErrorDefault`](#throwonerrordefault) | Default `throwOnError` value passed to your client. | `true` |
| [`validator`](#validator) | Pass Zod schemas to your client. | `false` |
| [`include`](https://kubb.dev/docs/5.x/reference/plugin-options#include) | Keep only operations that match. | None |
| [`exclude`](https://kubb.dev/docs/5.x/reference/plugin-options#exclude) | Skip operations that match. | `[]` |
| [`override`](https://kubb.dev/docs/5.x/reference/plugin-options#override) | Apply different options per pattern. | `[]` |
| [`resolver`](https://kubb.dev/docs/5.x/reference/plugin-options#resolver) | Customize generated names and file paths. | `resolverClient` |
| [`macros`](https://kubb.dev/docs/5.x/reference/plugin-options#macros) | Rewrite AST nodes before printing. | `[]`, run after the built-in client macros |
## Option details
### importPath
Import specifier of your client module. The plugin writes it into every generated import exactly as given, so it must resolve from the generated file. Use a relative path, a package name, or an alias.
| | |
| -------- | -------- |
| Type | `string` |
| Required | `true` |
```typescript
pluginClient({ importPath: '../../../client' }) // relative to src/gen/clients//
pluginClient({ importPath: '@my-org/api-client' }) // a package
```
With `group: { type: 'tag' }` and `output.path: 'clients'`, a generated file sits in `src/gen/clients//`, so `../../../client` points at `src/client.ts`. Without `group` it is `../../client`.
The module must export `client`, plus the `Options` and `RequestResult` types. See [write your client](https://kubb.dev/extensions/kubb-labs/plugin-client/guides/write-your-client).
### throwOnErrorDefault
Default for the `throwOnError` field that every generated function passes to your client. A call that sets `throwOnError` itself wins. Your client decides what the flag does: the [example client](https://kubb.dev/extensions/kubb-labs/plugin-client/guides/write-your-client) throws on a non-2xx status when it is `true` and returns the error as a value when it is `false`.
| | |
| -------- | --------- |
| Type | `boolean` |
| Required | `false` |
| Default | `true` |
The setting applies to the whole plugin, so you cannot set it in `override`.
### validator
Passes Zod schemas from `@kubb/plugin-zod` to your client on `config.validator`. The plugin does not run the schemas. Your client reads `config.validator` and runs them. See [validate requests and responses](https://kubb.dev/extensions/kubb-labs/plugin-client/guides/validate-requests-and-responses).
| | |
| -------- | --------------------------------------------------------- |
| Type | `false \| 'zod' \| { request?: 'zod'; response?: 'zod' }` |
| Required | `false` |
| Default | `false` |
::field-group
:::field{name="false"}
Default value. Passes nothing.
:::
:::field{name="'zod'"}
Passes the response and error schemas.
:::
:::field{name="{ request?: 'zod', response?: 'zod' }"}
Opts in per direction.
:::
::
> [!IMPORTANT]
> Add `pluginZod()` to the plugins list when `validator` is set. Generation stops with an error if it is missing.
---
- **Page:** Axios · @kubb/plugin-axios · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-axios
- **Description:** Generates a type-safe axios client from your OpenAPI spec, one async function per operation, so each call stays in sync with the API.
# Axios
The Axios plugin turns each operation in your OpenAPI spec into a typed async function that sends the request with axios. Each function takes grouped `path`, `query`, `headers`, and `body` parameters and returns a result keyed by status code.
The query plugins (`@kubb/plugin-react-query`, `@kubb/plugin-vue-query`, and `@kubb/plugin-swr`) and `@kubb/plugin-mcp` call these functions. The plugin also copies its runtime files (`client.ts`, `serializers.ts`, and `standardSchema.ts`) to `.kubb/` in the root output folder.
## Installation
::code-group{sync="package-manager"}
```shell [bun]
bun add -d @kubb/plugin-axios
```
```shell [pnpm]
pnpm add -D @kubb/plugin-axios
```
```shell [npm]
npm install --save-dev @kubb/plugin-axios
```
```shell [yarn]
yarn add -D @kubb/plugin-axios
```
::
Or run `kubb add plugin-axios` to install the version the [Kubb registry](/registry) pins and add `pluginAxios()` to `kubb.config.ts`.
## Setup
- Add `@kubb/plugin-ts` for the operation types, or `@kubb/plugin-zod` with `inferred: true`.
- Add `@kubb/plugin-zod` when you set `validator`, and install `zod` v4. Without the plugin, `validator` does nothing.
- Install `axios` 1.20 or a later v1 release in the app that uses the generated code.
## Options worth knowing
- `baseURL` is prepended to every request. The spec's `servers` URL is not used, so without `baseURL` you set one at runtime with `client.setConfig({ baseURL })`.
- `validator: 'zod'` validates response bodies with the schemas from `@kubb/plugin-zod`. Use `{ request: 'zod', response: 'zod' }` to also validate request bodies.
- `throwOnErrorDefault: false` returns non-2xx responses as values instead of throwing. A single call can still pass `throwOnError`.
- `returnType: 'data'` makes a call resolve to the success body instead of the full result. With `throwOnError: false`, the call still returns the full result.
- `sdk` generates a class-based SDK, grouped by tag or flat, instead of standalone functions. The query plugins and `@kubb/plugin-mcp` need the standalone functions, so leave `sdk` unset when you use them.
See [Options](https://kubb.dev/extensions/kubb-labs/plugin-axios/options) for every option and its default.
## Example
The config below generates an axios client that sends every request to the Petstore API.
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { pluginTs } from '@kubb/plugin-ts'
import { pluginAxios } from '@kubb/plugin-axios'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
plugins: [
pluginTs(),
pluginAxios({ baseURL: 'https://petstore.swagger.io/v2' }),
],
})
```
---
- **Page:** Options · MCP · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-mcp/options
- **Description:** Configuration options for @kubb/plugin-mcp.
# Options
Pass these options to `pluginMcp()`. Shared options link to [Shared plugin options](https://kubb.dev/docs/5.x/reference/plugin-options).
## Options overview
| Option | Purpose | Default |
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------- | -------------------------------------------- |
| [`output`](#output) | Where handlers are written: `path`, `mode`, `barrel`, `banner`, `footer`. | `{ path: 'mcp', barrel: { type: 'named' } }` |
| [`group`](https://kubb.dev/docs/5.x/reference/plugin-options#group) | Split output by tag or path: `type`, `name`. | None |
| [`client`](#client) | Which registered client plugin the handlers call. | Auto-detected |
| [`include`](https://kubb.dev/docs/5.x/reference/plugin-options#include) | Keep only operations that match. | None |
| [`exclude`](https://kubb.dev/docs/5.x/reference/plugin-options#exclude) | Skip operations that match. | `[]` |
| [`override`](https://kubb.dev/docs/5.x/reference/plugin-options#override) | Apply different options per pattern. | `[]` |
| [`resolver`](#resolver) | Customize generated names and file paths. | `resolverMcp` |
| [`macros`](https://kubb.dev/docs/5.x/reference/plugin-options#macros) | Rewrite AST nodes before printing. | `[]` |
## Option details
### output
Where the generated MCP handler files are written. The plugin writes `server.ts`, `start.ts`, and `.mcp.json` at the root of `output.path`, next to the handlers. Keep `output.path` a folder name such as the default `'mcp'`. Single-file output (`output.mode: 'file'`, or a `path` with an extension) has no room for those files. With `group`, handlers move into subfolders and those files stay at the root.
| | |
| -------- | -------------------------------------------- |
| Type | `Output` |
| Required | `false` |
| Default | `{ path: 'mcp', barrel: { type: 'named' } }` |
### client
Selects which registered client plugin the handlers call. A single registered client is auto-detected. Set `client` when several are registered.
| | |
| -------- | -------------------- |
| Type | `'fetch' \| 'axios'` |
| Required | `false` |
::field-group
:::field{name="'fetch'"}
Calls the operations generated by [`@kubb/plugin-fetch`](https://kubb.dev/extensions/kubb-labs/plugin-fetch).
:::
:::field{name="'axios'"}
Calls the operations generated by [`@kubb/plugin-axios`](https://kubb.dev/extensions/kubb-labs/plugin-axios).
:::
::
Each handler passes grouped `{ path, query, headers, body }` options. Configure transport settings such as `baseURL` on the client plugin.
Generated handlers follow the client plugin's `returnType` option. With `'full'` (the client default) handlers read the success body from `res.data`, and with `'data'` they use the resolved call result directly as the tool response body. Handlers always pass `throwOnError: true` so non-2xx responses throw and surface as tool errors, regardless of the client's `throwOnErrorDefault`.
> [!NOTE]
> The handlers call a client plugin's functions, so register `@kubb/plugin-fetch` or `@kubb/plugin-axios` alongside this one.
### resolver
Overrides generated file and symbol names. Omitted members keep `resolverMcp`. The shared members (`name`, `file`, `imports`) and the `this` context are described under [`resolver`](https://kubb.dev/docs/5.x/reference/plugin-options#resolver).
| | |
| -------- | ---------------------------- |
| Type | `ResolverPatch` |
| Required | `false` |
```typescript [Partial override]
type ResolverMcpPatch = {
name?(name: string): string
file?: {
baseName?(params: { name: string; extname: string }): string
path?(params: { baseName: string; output: Output }): string
}
imports?(options: ResolveImportsOptions): Array
handler?: {
name?(node: OperationNode): string // → 'showPetByIdHandler'
}
}
```
---
- **Page:** Storage · Kubb
- **Source:** https://kubb.dev/docs/5.x/reference/kit/storage
- **Description:** Storage backends decide where generated files are written. Covers createStorage, the Storage interface, and the built-in fsStorage and memoryStorage backends.
# Storage
Storage backends persist generated files in the filesystem, memory, or a custom destination.
## `createStorage`
`createStorage` takes a builder function `(options: TOptions) => Storage` and returns a factory `(options?: TOptions) => Storage`. Call the returned factory to create a backend.
```typescript twoslash [memory-storage.ts]
import { createStorage } from 'kubb/kit'
export const memoryStorage = createStorage(() => {
const store = new Map()
return {
name: 'memory',
async readItem(key) {
return store.get(key) ?? null
},
async writeItem(key, value) {
store.set(key, value)
},
async removeItem(key) {
store.delete(key)
},
async readKeys(base) {
const keys = [...store.keys()]
return base ? keys.filter((k) => k.startsWith(base)) : keys
},
async empty(base) {
if (!base) return store.clear()
for (const k of store.keys()) if (k.startsWith(base)) store.delete(k)
},
}
})
```
## `Storage` interface {#storage-interface}
The engine consumes this interface and exposes the backend through the build result.
| Method | Params | Returns | Purpose |
| -------------- | ---------------------------- | ------------------------- | --------------------------------------------- |
| `readItem()` | `key: string` | `Promise` | Retrieve an item's content |
| `writeItem()` | `key: string, value: string` | `Promise` | Write an item |
| `removeItem()` | `key: string` | `Promise` | Delete an item |
| `readKeys()` | `base?: string` | `Promise` | List keys, optionally filtered by prefix |
| `empty()` | `base?: string` | `Promise` | Delete all items, optionally scoped by prefix |
Omitting `base` on `empty()` is implementation-defined. `memoryStorage` wipes every entry, while the filesystem-backed `fsStorage` treats a missing `base` as a no-op and deletes nothing.
Every method is required. `readItem` returns `null` for a missing key. Kubb can skip `writeItem` for a file whose content did not change, so do not expect one call per generated file.
## `fsStorage`
`fsStorage` is the default backend. It writes under `output.path` and creates directories as needed.
## `memoryStorage`
`memoryStorage` writes nothing to disk, so it suits plugin tests, CI validation, and dry runs.
Both ship from `kubb/kit` and go straight into the config's `storage` field.
---
- **Page:** MCP · @kubb/plugin-mcp · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-mcp
- **Description:** Generates a Model Context Protocol server from your OpenAPI spec, so AI assistants can call each operation as a typed tool.
# MCP
The MCP plugin turns each operation into a typed MCP tool that AI assistants can call. Each tool uses Zod schemas from `@kubb/plugin-zod` for its input and output.
Each tool handler calls the function a client plugin generates for that operation. The plugin writes `server.ts`, `start.ts`, and `.mcp.json` at the root of its `output.path`. `start.ts` calls the `startServer()` that `server.ts` exports, and `.mcp.json` runs `start.ts` to start a stdio server.
## Installation
::code-group{sync="package-manager"}
```shell [bun]
bun add -d @kubb/plugin-mcp
```
```shell [pnpm]
pnpm add -D @kubb/plugin-mcp
```
```shell [npm]
npm install --save-dev @kubb/plugin-mcp
```
```shell [yarn]
yarn add -D @kubb/plugin-mcp
```
::
Or run `kubb add plugin-mcp` to install the version the [Kubb registry](/registry) pins and add `pluginMcp()` to `kubb.config.ts`.
## Setup
- Add `@kubb/plugin-ts`, `@kubb/plugin-zod`, and a client plugin: `@kubb/plugin-fetch` or `@kubb/plugin-axios`. Leave `sdk` unset on the client plugin.
- Install `@modelcontextprotocol/server` v2 and `zod` 4.2 or a later v4 release in the app that runs the server. Add `axios` too when you use `@kubb/plugin-axios`.
- Install a TypeScript runner such as `tsx`. The generated `.mcp.json` runs `npx tsx`, which downloads `tsx` from npm when it is missing.
- Copy the server entry from the generated `.mcp.json` into the `.mcp.json` your MCP client reads, such as the one at the project root for Claude Code.
## Options worth knowing
- `client` picks `fetch` or `axios` when both client plugins are registered. A single client is detected automatically.
- `output.path` must be a folder name, such as the default `mcp`, because single-file output has no place for `server.ts`, `start.ts`, and `.mcp.json`.
The `args` path in `.mcp.json` points at `start.ts` relative to the Kubb `root`, because MCP clients start the command from their own working directory. Use an absolute path for a client that starts in another folder, or point it at your own entry file to run setup code before `startServer()`.
See [Options](https://kubb.dev/extensions/kubb-labs/plugin-mcp/options) for every option and its default.
## Example
The config below generates an MCP server whose tools call the Petstore API through `@kubb/plugin-fetch`.
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { pluginTs } from '@kubb/plugin-ts'
import { pluginZod } from '@kubb/plugin-zod'
import { pluginFetch } from '@kubb/plugin-fetch'
import { pluginMcp } from '@kubb/plugin-mcp'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
plugins: [
pluginTs(),
pluginZod(),
pluginFetch({ baseURL: 'https://petstore.swagger.io/v2' }),
pluginMcp({ output: { path: 'mcp', mode: 'directory' } }),
],
})
```
---
- **Page:** Client · @kubb/plugin-client · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-client
- **Description:** Generates typed operation functions from your OpenAPI spec that call a client module you own, so you decide the transport, auth, and error handling.
# Client
The Client plugin turns each operation in your OpenAPI spec into a typed function that calls a client module you write. The generated code has no Fetch, axios, or Kubb runtime dependency.
Each function takes grouped `path`, `query`, `headers`, and `body` parameters and passes the operation's auth requirements to your client in a `security` list. A single call can pass its own `client` to replace the default. For a ready-made client, or to use the query plugins or `@kubb/plugin-mcp`, use `@kubb/plugin-fetch` or `@kubb/plugin-axios` instead.
## Installation
::code-group{sync="package-manager"}
```shell [bun]
bun add -d @kubb/plugin-client
```
```shell [pnpm]
pnpm add -D @kubb/plugin-client
```
```shell [npm]
npm install --save-dev @kubb/plugin-client
```
```shell [yarn]
yarn add -D @kubb/plugin-client
```
::
Or run `kubb add plugin-client` to install the version the [Kubb registry](/registry) pins and add `pluginClient()` to `kubb.config.ts`.
## Setup
- Set the required `importPath` option to your client module. The module must export `client` and the `Options` and `RequestResult` types. When the spec has server-sent event operations, it must also export `toEventStream` and the `EventStreamResult` and `SuccessOf` types.
- Add `@kubb/plugin-ts` for the operation types, or `@kubb/plugin-zod` with `inferred: true`.
- Add `@kubb/plugin-zod` when you set `validator`, and install `zod` v4. Generation fails without the plugin.
## Options worth knowing
- `importPath` is written into every generated import as given, so it must resolve from the generated file. A relative path, a package name, or an alias works.
- `validator: 'zod'` passes response schemas from `@kubb/plugin-zod` to your client. Use `{ request: 'zod', response: 'zod' }` to also pass request body schemas.
- `throwOnErrorDefault` is the `throwOnError` value each call passes to your client. The default is `true`.
See [Options](https://kubb.dev/extensions/kubb-labs/plugin-client/options) for every option and its default.
## Example
The config below groups the generated functions by tag and points them at the client module in `src/client.ts`.
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { pluginTs } from '@kubb/plugin-ts'
import { pluginClient } from '@kubb/plugin-client'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
plugins: [
pluginTs(),
pluginClient({
output: { path: 'clients', mode: 'directory', barrel: { type: 'named' } },
group: { type: 'tag' },
// resolved from each generated file: src/gen/clients// to src/client.ts
importPath: '../../../client',
}),
],
})
```
---
- **Page:** Fetch · @kubb/plugin-fetch · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-fetch
- **Description:** Generates a type-safe Fetch API client from your OpenAPI spec, one async function per operation, so each call stays in sync with the API.
# Fetch
The Fetch plugin turns each operation in your OpenAPI spec into a typed async function that sends the request with the native Fetch API. Each function takes grouped `path`, `query`, `headers`, and `body` parameters and returns a result keyed by status code.
The query plugins (`@kubb/plugin-react-query`, `@kubb/plugin-vue-query`, and `@kubb/plugin-swr`) and `@kubb/plugin-mcp` call these functions. The plugin also copies its runtime files (`client.ts`, `serializers.ts`, and `standardSchema.ts`) to `.kubb/` in the root output folder.
## Installation
::code-group{sync="package-manager"}
```shell [bun]
bun add -d @kubb/plugin-fetch
```
```shell [pnpm]
pnpm add -D @kubb/plugin-fetch
```
```shell [npm]
npm install --save-dev @kubb/plugin-fetch
```
```shell [yarn]
yarn add -D @kubb/plugin-fetch
```
::
Or run `kubb add plugin-fetch` to install the version the [Kubb registry](/registry) pins and add `pluginFetch()` to `kubb.config.ts`.
## Setup
- Add `@kubb/plugin-ts` for the operation types, or `@kubb/plugin-zod` with `inferred: true`.
- Add `@kubb/plugin-zod` when you set `validator`, and install `zod` v4. Without the plugin, `validator` does nothing.
- No HTTP client package is needed. The generated code calls the global `fetch`.
## Options worth knowing
- `baseURL` is prepended to every request. The spec's `servers` URL is not used, so without `baseURL` you set one at runtime with `client.setConfig({ baseURL })`.
- `validator: 'zod'` validates response bodies with the schemas from `@kubb/plugin-zod`. Use `{ request: 'zod', response: 'zod' }` to also validate request bodies.
- `throwOnErrorDefault: false` returns non-2xx responses as values instead of throwing. A single call can still pass `throwOnError`.
- `returnType: 'data'` makes a call resolve to the success body instead of the full result. With `throwOnError: false`, the call still returns the full result.
- `sdk` generates a class-based SDK, grouped by tag or flat, instead of standalone functions. The query plugins and `@kubb/plugin-mcp` need the standalone functions, so leave `sdk` unset when you use them.
See [Options](https://kubb.dev/extensions/kubb-labs/plugin-fetch/options) for every option and its default.
## Example
The config below generates a Fetch client that sends every request to the Petstore API.
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { pluginTs } from '@kubb/plugin-ts'
import { pluginFetch } from '@kubb/plugin-fetch'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
plugins: [
pluginTs(),
pluginFetch({ baseURL: 'https://petstore.swagger.io/v2' }),
],
})
```
---
- **Page:** Options · Cypress · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-cypress/options
- **Description:** Configuration options for @kubb/plugin-cypress.
# Options
Pass these options to `pluginCypress()`. Shared options link to [Shared plugin options](https://kubb.dev/docs/5.x/reference/plugin-options).
## Options overview
| Option | Purpose | Default |
| ------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------ |
| [`output`](https://kubb.dev/docs/5.x/reference/plugin-options#output) | Where files are written: `path`, `mode`, `barrel`, `banner`, `footer`. | `{ path: 'cypress', barrel: { type: 'named' } }` |
| [`group`](https://kubb.dev/docs/5.x/reference/plugin-options#group) | Split output by tag or path: `type`, `name`. | None |
| [`baseURL`](#baseurl) | Base URL prepended to every request. | None |
| [`include`](https://kubb.dev/docs/5.x/reference/plugin-options#include) | Keep only operations that match. | None |
| [`exclude`](https://kubb.dev/docs/5.x/reference/plugin-options#exclude) | Skip operations that match. | `[]` |
| [`override`](https://kubb.dev/docs/5.x/reference/plugin-options#override) | Apply different options per pattern. | `[]` |
| [`resolver`](https://kubb.dev/docs/5.x/reference/plugin-options#resolver) | Customize generated names and file paths. | `resolverCypress` |
| [`macros`](https://kubb.dev/docs/5.x/reference/plugin-options#macros) | Rewrite AST nodes before printing. | `[]` |
`resolverCypress` adds no namespaces of its own, so a `resolver` patch uses only the shared `name`, `file` and `imports` members.
## Option details
### baseURL
Base URL prepended to every request in the generated helpers. When omitted, no host is prepended and each helper uses the operation's relative path from the spec. The host is emitted into each helper's URL, so no runtime host setup is needed.
| | |
| -------- | -------- |
| Type | `string` |
| Required | `false` |
```typescript [baseURL: 'https://staging.petstore.dev']
export function showPetById(
{ path }: ShowPetByIdOptions,
options: Partial = {},
): Cypress.Chainable {
return cy
.request({
method: 'GET',
url: `https://staging.petstore.dev/pets/${path.petId}`,
...options,
})
.then((res) => res.body)
}
```
---
- **Page:** Options · Barrel · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-barrel/options
- **Description:** Configuration options for @kubb/plugin-barrel.
# Options
`pluginBarrel` takes no arguments. You configure it through `output.barrel`, either on `defineConfig` to set the root barrel and the default every plugin inherits, or on a single plugin to override that plugin's barrel. The plugin-level behavior is also summarized under [`output.barrel`](https://kubb.dev/docs/5.x/reference/plugin-options#output-barrel) in the shared plugin options.
## Options overview
| Option | Purpose | Default |
| ----------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------- |
| [`output.barrel`](#output-barrel) | Re-export style for the barrel files. | `false` on `defineConfig`, `{ type: 'named' }` in every generator plugin's default `output` |
| ↳ [`output.barrel.type`](#type) | Named exports or a wildcard export. | Required when `output.barrel` is an object |
| ↳ [`output.barrel.nested`](#nested) | Choose whether barrels reference subdirectory barrels. | `false` |
## Option details
### output.barrel
Kubb writes an `index.ts` in every directory of a plugin's output, and a root barrel when `output.barrel` is set on `defineConfig`. For two plugins that write to `models` and `clients`, with `output.barrel` set on `defineConfig`:
```text
src/gen
├── index.ts root barrel
├── models
│ ├── index.ts plugin barrel
│ ├── Pet.ts
│ └── User.ts
└── clients
├── index.ts plugin barrel
├── pet
│ ├── index.ts
│ └── getPetById.ts
└── store
├── index.ts
└── getInventory.ts
```
| | |
| -------- | ------------------------------------------------------- |
| Type | `{ type: 'all' \| 'named', nested?: boolean } \| false` |
| Required | `false` |
| Default | `false` |
The `type` field picks the export style. A plugin's `output.barrel` also accepts `nested`, so each barrel re-exports the barrels below it instead of the leaf files. The root `output.barrel` has no `nested` field and always stays flat.
A plugin called without `output` uses its own default, which sets `barrel: { type: 'named' }`. If you pass your own `output` object, it replaces that default. `pluginTs({ output: { path: 'types' } })` then has no `barrel` and uses `config.output.barrel`, which is `false` unless you set it.
Set `barrel: { type: 'named' | 'all' }` on `defineConfig` to enable barrels everywhere: a root barrel, and the default every plugin without its own `output.barrel` inherits. A plugin that sets its own `output.barrel` overrides that inherited value, including back to `false`, which also drops its files from the root barrel. A plugin with `output.mode: 'file'` gets no barrel of its own, and the root barrel re-exports that file directly.
### type
Export style for the barrel files. Required whenever `output.barrel` is set to an object.
| | |
| -------- | ------------------ |
| Type | `'all' \| 'named'` |
| Required | `true` |
::field-group
:::field{name="'named'"}
Re-exports each symbol by name from the file's named exports. Best for tree-shaking and explicit imports.
:::
:::field{name="'all'"}
Uses `export *`, a smaller barrel that re-exports everything.
:::
::
::code-group
```typescript ['named']
// src/gen/index.ts
export { getUser } from './api/user'
export { getPost, Post } from './api/post'
export { User } from './api/types/User'
```
```typescript ['all']
// src/gen/index.ts
export * from './api/user'
export * from './api/post'
export * from './api/types/User'
```
::
### nested
Changes what each barrel references. A barrel is written for every directory either way. With `nested: false`, the plugin's top barrel reaches through to the leaf files. With `nested: true`, each barrel re-exports only what sits directly inside its directory, including the subdirectory barrels below it, so callers can import from any depth. This field works on a plugin's `output.barrel` only.
| | |
| -------- | --------- |
| Type | `boolean` |
| Required | `false` |
| Default | `false` |
::code-group
```typescript [nested: false (default) → barrels reference leaf files]
// src/gen/api/index.ts
export * from './user'
export * from './post'
export * from './types/User'
// src/gen/api/types/index.ts
export * from './User'
```
```typescript [nested: true → barrels reference sub-barrels]
// src/gen/api/index.ts re-exports its files and subdirectories
export * from './user'
export * from './post'
export * from './types'
// src/gen/api/types/index.ts re-exports its files
export * from './User'
```
::
---
- **Page:** React Query · @kubb/plugin-react-query · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-react-query
- **Description:** Generates typed TanStack Query helpers for React from your OpenAPI spec: queryOptions and mutationOptions factories with their cache keys. Set hooks to also get useQuery and useMutation hooks, plus useInfiniteQuery when infinite is set.
# React Query
The React Query plugin generates TanStack Query helpers for React from your OpenAPI spec. By default you get `queryOptions` and `mutationOptions` factories with their query and mutation keys. Set `hooks: true` to also get `useQuery` and `useMutation` hooks.
The plugin ships no HTTP client. Each helper calls a function generated by a client plugin.
## Installation
::code-group{sync="package-manager"}
```shell [bun]
bun add -d @kubb/plugin-react-query
```
```shell [pnpm]
pnpm add -D @kubb/plugin-react-query
```
```shell [npm]
npm install --save-dev @kubb/plugin-react-query
```
```shell [yarn]
yarn add -D @kubb/plugin-react-query
```
::
Or run `kubb add plugin-react-query` to install the version the [Kubb registry](/registry) pins and add `pluginReactQuery()` to `kubb.config.ts`.
## Setup
- Add `@kubb/plugin-ts` and a client plugin: `@kubb/plugin-fetch` or `@kubb/plugin-axios`. Leave `sdk` unset on the client plugin.
- Install `@tanstack/react-query` 5.82 or a later v5 release in the app that uses the generated code.
- Configure validation on the client plugin, not here.
## Options worth knowing
- `client` picks `fetch` or `axios` when both client plugins are registered. A single client is detected automatically.
- `hooks` adds the `use*` hooks on top of the option factories.
- `suspense: {}` adds `useSuspenseQuery` hooks. It needs `hooks: true`.
- `infinite` adds `useInfiniteQuery` hooks for pagination. It needs `hooks: true` and covers the operations that take the query parameter named in `infinite.queryParam`, which defaults to `'id'`.
- `query` and `mutation` set which HTTP methods become queries (`GET`) and mutations (`POST`, `PUT`, `PATCH`, `DELETE`). They also set where the TanStack Query runtime is imported from. Set either to `false` to skip those helpers.
- `customOptions: { importPath }` routes every hook through your own function that returns extra options. It needs `hooks: true`. Kubb creates a starter file at `importPath`, resolved from the generated hooks folder, when none exists and the path stays inside the plugin's output folder.
See [Options](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options) for every option and its default.
## Example
The config below generates `useQuery` and `useMutation` hooks that call the Fetch client.
```typescript [kubb.config.ts]
import { defineConfig } from 'kubb/config'
import { pluginTs } from '@kubb/plugin-ts'
import { pluginFetch } from '@kubb/plugin-fetch'
import { pluginReactQuery } from '@kubb/plugin-react-query'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
plugins: [
pluginTs(),
pluginFetch(),
pluginReactQuery({ hooks: true }),
],
})
```
---
- **Page:** Options · Faker · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-faker/options
- **Description:** Configuration options for @kubb/plugin-faker.
# Options
Pass these options to `pluginFaker()`, all of them optional. Shared options link to [Shared plugin options](https://kubb.dev/docs/5.x/reference/plugin-options).
## Options overview
| Option | Purpose | Default |
| ------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ---------------------------------------------- |
| [`output`](https://kubb.dev/docs/5.x/reference/plugin-options#output) | Where files are written: `path`, `mode`, `barrel`, `banner`, `footer`. | `{ path: 'mocks', barrel: { type: 'named' } }` |
| [`group`](https://kubb.dev/docs/5.x/reference/plugin-options#group) | Split output by tag or path: `type`, `name`. | None |
| [`typeMode`](#typemode) | Whether factory types come from the generated values or the declared model. | `'inferred'` |
| [`dateParser`](#dateparser) | Library that formats string date and time fields. | `'faker'` |
| [`regexGenerator`](#regexgenerator) | Library that turns a regex `pattern` into a string. | `'faker'` |
| [`locale`](#locale) | Faker locale code for the generated values. | `'en'` |
| [`seed`](#seed) | Value passed to `faker.seed(...)` for deterministic output. | None |
| [`include`](https://kubb.dev/docs/5.x/reference/plugin-options#include) | Keep only operations and schemas that match. | None |
| [`exclude`](https://kubb.dev/docs/5.x/reference/plugin-options#exclude) | Skip operations and schemas that match. | `[]` |
| [`override`](https://kubb.dev/docs/5.x/reference/plugin-options#override) | Apply different options per pattern. | `[]` |
| [`resolver`](#resolver) | Customize generated names and file paths. | `resolverFaker` |
| [`macros`](https://kubb.dev/docs/5.x/reference/plugin-options#macros) | Rewrite AST nodes before printing. | `[]` |
| [`printer`](#printer) | Replace the handler for a schema type. | None |
## Option details
### typeMode
Controls the input and return types of object and intersection factories. Both modes generate the same values and apply overrides with a shallow merge.
| | |
| -------- | ------------------------ |
| Type | `'inferred' \| 'schema'` |
| Required | `false` |
| Default | `'inferred'` |
::field-group
:::field{name="'inferred'"}
Default value. Derives return types from generated values and supplied overrides. Optional and nullable fields retain their concrete value types, and overrides preserve literal types.
:::
:::field{name="'schema'"}
Accepts `Partial` and returns the declared model type, including optional and nullable fields. Use it for fixtures you modify after creation.
:::
::
::code-group
```typescript ['inferred' (default)]
// export function createOrder = object>(data?: TData)
const order = createOrder({ quantity: 2, complete: true })
const complete: true = order.complete
// TypeScript error: false is not assignable to true.
order.complete = false
```
```typescript ['schema']
// export function createOrder(data?: Partial): Order
const order = createOrder({ quantity: 2, complete: true })
order.complete = false
// TypeScript error: foo does not exist in Partial.
createOrder({ quantity: 2, foo: '' })
```
::
Use [`override`](https://kubb.dev/docs/5.x/reference/plugin-options#override) to select a mode for matching schemas. String patterns are regular expressions, so `'^Order$'` matches only the `Order` schema:
```typescript [kubb.config.ts]
pluginFaker({
override: [{ type: 'schemaName', pattern: '^Order$', options: { typeMode: 'schema' } }],
})
```
### dateParser
Library used to format `date` and `time` fields represented as strings. Pick a value other than `'faker'` when your project already uses a date library, and install that library in the consuming app. Generated `date` and `time` strings use `YYYY-MM-DD` and `HH:mm:ss`, and `date-time` values keep the ISO string.
| | |
| -------- | ------------------------------------------ |
| Type | `'faker' \| 'dayjs' \| 'moment' \| string` |
| Required | `false` |
| Default | `'faker'` |
::field-group
:::field{name="'faker'"}
Default value. Renders a `date` field as `faker.date.anytime().toISOString().substring(0, 10)`.
:::
:::field{name="'dayjs'"}
Renders it as `dayjs(faker.date.anytime()).format('YYYY-MM-DD')`.
:::
:::field{name="'moment'"}
Renders it as `moment(faker.date.anytime()).format('YYYY-MM-DD')`.
:::
:::field{name="Custom module"}
Pass a module name that exports a default formatting function. Kubb adds the import to generated files.
:::
::
### regexGenerator
Library used to generate strings that satisfy a regex `pattern` in the spec.
| | |
| -------- | ---------------------- |
| Type | `'faker' \| 'randexp'` |
| Required | `false` |
| Default | `'faker'` |
::field-group
:::field{name="'faker'"}
Default value. Generates `faker.helpers.fromRegExp(pattern)` without an extra dependency.
:::
:::field{name="'randexp'"}
Generates `new RandExp(pattern).gen()`. Supports a wider regex grammar and requires the `randexp` runtime dependency.
:::
::
### locale
Faker locale code. It switches the named import to `fakerXX` from `@faker-js/faker`, so generated values reflect the target region. The default `'en'` imports `fakerEN`, `'de'` imports `fakerDE`, and `'de_AT'` imports `fakerDE_AT`. See [Faker.js localization](https://fakerjs.dev/api/localization.html) for all locale codes.
| | |
| -------- | -------- |
| Type | `string` |
| Required | `false` |
| Default | `'en'` |
### seed
Kubb passes this value to `faker.seed(...)` at the top of each factory, so every run returns the same data. Use it for snapshot tests. Pass a single number or an array of numbers. Factories still accept overrides, such as `createPet({ name: 'Rex' })`.
| | |
| -------- | -------------------- |
| Type | `number \| number[]` |
| Required | `false` |
### resolver
Overrides generated file and symbol names. Omitted members keep `resolverFaker`. The shared members (`name`, `file`, `imports`) and the `this` context are described under [`resolver`](https://kubb.dev/docs/5.x/reference/plugin-options#resolver).
| | |
| -------- | ------------------------------ |
| Type | `ResolverPatch` |
| Required | `false` |
::code-collapse{name="ResolverFaker patch members"}
```typescript [Partial override]
type ResolverFakerPatch = {
name?(name: string): string
file?: {
baseName?(params: { name: string; extname: string }): string
path?(params: { baseName: string; output: Output }): string
}
imports?(options: ResolveImportsOptions): Array
param?: {
name?(node: OperationNode, param: ParameterNode): string // → 'showPetByIdPathPetId'
path?(node: OperationNode, param: ParameterNode): string // → 'createShowPetByIdPath'
query?(node: OperationNode, param: ParameterNode): string // → 'createListPetsQuery'
headers?(node: OperationNode, param: ParameterNode): string // → 'createDeletePetHeaders'
}
response?: {
status?(node: OperationNode, statusCode: StatusCode): string // → 'listPetsStatus200'
body?(node: OperationNode): string // → 'createPetsBody'
response?(node: OperationNode): string // → 'listPetsResponse'
responses?(node: OperationNode): string // → 'listPetsResponses'
}
}
```
::
### printer
Replaces the Faker node handler for a specific schema type, such as `'integer'`, `'date'`, or `'string'`. Each handler returns the Faker expression as a string. Use `this.transform` to recurse into nested nodes and `this.options` to read printer options. The [printer guide](https://kubb.dev/docs/5.x/how-to/printers) covers how overrides compose with macros.
| | |
| -------- | ------------------------------- |
| Type | `{ nodes?: PrinterFakerNodes }` |
| Required | `false` |
```typescript [Map integer schemas to a float]
import { pluginFaker } from '@kubb/plugin-faker'
pluginFaker({
printer: {
nodes: {
integer() {
return 'faker.number.float()'
},
},
},
})
```
---
- **Page:** Options · React Query · Kubb
- **Source:** https://kubb.dev/extensions/kubb-labs/plugin-react-query/options
- **Description:** Configuration options for @kubb/plugin-react-query.
# Options
Pass these options to `pluginReactQuery()`. Shared options link to [Shared plugin options](https://kubb.dev/docs/5.x/reference/plugin-options) for details.
## Options overview
| Option | Purpose | Default |
| ------------------------------------------------------------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| [`output`](https://kubb.dev/docs/5.x/reference/plugin-options#output) | Where files are written: `path`, `mode`, `barrel`, `banner`, `footer`. | `{ path: 'hooks', barrel: { type: 'named' } }` |
| [`group`](https://kubb.dev/docs/5.x/reference/plugin-options#group) | Split output by tag or path: `type`, `name`. | None |
| [`client`](#client) | Which registered client plugin the hooks call. | Auto-detected |
| [`infinite`](#infinite) | Generate `useInfiniteQuery` hooks for pagination. | `false` |
| [`suspense`](#suspense) | Generate `useSuspenseQuery` hooks. | `false` |
| [`query`](#query) | Configure the query hooks. | `{ methods: ['GET'], importPath: '@tanstack/react-query' }` |
| [`queryKey`](#querykey) | Build the `queryKey` for each query hook. | Built-in `queryKeyTransformer` |
| [`mutation`](#mutation) | Configure the mutation hooks. | `{ methods: ['POST', 'PUT', 'PATCH', 'DELETE'], importPath: '@tanstack/react-query' }` |
| [`mutationKey`](#mutationkey) | Build the `mutationKey` for each mutation hook. | Built-in `mutationKeyTransformer` |
| [`customOptions`](#customoptions) | Route every hook through your own options function. | None |
| [`hooks`](#hooks) | Emit `use*` hook functions on top of the factories. | `false` |
| [`include`](https://kubb.dev/docs/5.x/reference/plugin-options#include) | Keep only operations that match. | None |
| [`exclude`](https://kubb.dev/docs/5.x/reference/plugin-options#exclude) | Skip operations that match. | `[]` |
| [`override`](https://kubb.dev/docs/5.x/reference/plugin-options#override) | Apply different options per pattern. | `[]` |
| [`resolver`](#resolver) | Customize generated names and file paths. | `resolverReactQuery` |
| [`macros`](https://kubb.dev/docs/5.x/reference/plugin-options#macros) | Rewrite AST nodes before printing. | `[]` |
## Option details
### client
Selects which registered client plugin the hooks call. A single registered client is auto-detected. Set `client` when several are registered.
| | |
| -------- | -------------------- |
| Type | `'axios' \| 'fetch'` |
| Required | `false` |
::field-group
:::field{name="'fetch'"}
Calls the operations generated by [`@kubb/plugin-fetch`](https://kubb.dev/extensions/kubb-labs/plugin-fetch).
:::
:::field{name="'axios'"}
Calls the operations generated by [`@kubb/plugin-axios`](https://kubb.dev/extensions/kubb-labs/plugin-axios).
:::
::
### infinite
Adds `infiniteQueryOptions` and `useInfiniteQuery` for operations that declare the query parameter named in `infinite.queryParam`. Needs [`hooks: true`](#hooks).
| | |
| -------- | ---------------------------- |
| Type | `Partial \| false` |
| Required | `false` |
| Default | `false` |
#### infinite.queryParam
Query parameter that carries the page cursor.
| | |
| -------- | -------- |
| Type | `string` |
| Required | `false` |
| Default | `'id'` |
#### infinite.initialPageParam
Initial value for `pageParam` on the first fetch.
| | |
| -------- | --------- |
| Type | `unknown` |
| Required | `false` |
| Default | `0` |
#### infinite.nextParam
Path to the next-page cursor on the response, as dot notation (`'pagination.next.id'`) or array form (`['pagination', 'next', 'id']`).
| | |
| -------- | --------------------------------- |
| Type | `string \| Array \| null` |
| Required | `false` |
| Default | `null` |
#### infinite.previousParam
Path to the previous-page cursor on the response, in the same dot or array form.
| | |
| -------- | --------------------------------- |
| Type | `string \| Array \| null` |
| Required | `false` |
| Default | `null` |
#### infinite.cursorParam
Deprecated path to the cursor field, read for both `getNextPageParam` and `getPreviousPageParam` when set. Use `nextParam` and `previousParam` instead.
| | |
| -------- | ---------------- |
| Type | `string \| null` |
| Required | `false` |
| Default | `null` |
#### infinite.getNextPageParam
Source code for TanStack Query's `getNextPageParam`, copied into the generated code as written. Use it when the next page must be computed instead of read from a field. Takes precedence over `nextParam` and `cursorParam`.
| | |
| -------- | ---------------- |
| Type | `string \| null` |
| Required | `false` |
| Default | `null` |
```typescript
infinite: {
queryParam: 'page',
getNextPageParam: '(lastPage) => (lastPage.hasNext ? lastPage.number + 1 : undefined)',
getPreviousPageParam: '(firstPage) => (firstPage.number > 0 ? firstPage.number - 1 : undefined)',
}
```
Without `getNextPageParam`, `nextParam` or `cursorParam`, the hook counts pages up from `initialPageParam` until a page is an empty array. This works only for array responses, so generation warns when the response is an object.
#### infinite.getPreviousPageParam
Source code for TanStack Query's `getPreviousPageParam`, copied into the generated code as written. Takes precedence over `previousParam` and `cursorParam`.
| | |
| -------- | ---------------- |
| Type | `string \| null` |
| Required | `false` |
| Default | `null` |
### suspense
Adds `useSuspenseQuery` hooks next to the regular query hooks. Pass `{}` to turn it on. Needs TanStack Query v5 or higher and [`hooks: true`](#hooks).
| | |
| -------- | -------------------------- |
| Type | `Partial