Options
| Option | Type | Default | Description |
|---|---|---|---|
output | Output | { path: 'types' } | Where the generated files are written and exported |
group | Group | — | Split output into per-tag or per-path folders |
enum | EnumOptions | { type: 'asConst', … } | How enums are generated and cased |
syntaxType | 'type' | 'interface' | 'type' | Emit object schemas as type aliases or interfaces |
optionalType | 'questionToken' | 'undefined' | 'questionTokenAndUndefined' | 'questionToken' | How optional properties are written |
arrayType | 'array' | 'generic' | 'array' | Type[] or Array<Type> |
include | Array<Include> | — | Keep only operations that match |
exclude | Array<Exclude> | — | Skip operations that match |
override | Array<Override> | — | Apply different options per pattern |
resolver | ResolverPatch<ResolverTs> | — | Customize generated names and file paths |
macros | Array<Macro> | — | Rewrite AST nodes before printing |
printer | { nodes?: PrinterTsNodes } | — | Replace the handler for a schema type |
output
Where the generated .ts files are written and how they are exported.
output.path
Folder where the plugin writes its files (string, default 'types'), resolved against the global output.path on defineConfig.
output.mode
How generated code is consolidated into files. Defaults to 'file'.
'file'writes everything into a single file, sooutput.pathneeds a file extension such as'types.ts'.'directory'writes one file per operation or schema underoutput.path.
output.barrel
Toggle the export style and depth to see the generated barrels.
- src/gen/
- models/
- Pet.ts
- User.ts
- clients/
- pet/
- getPetById.ts
- store/
- getInventory.ts
Controls how the generated index.ts (barrel) re-exports the output. Accepts { type: 'named' } or { type: 'all' }, optionally with nested: true (for example { type: 'named', nested: true }) to write an index.ts in every subdirectory, or false to skip the barrel entirely. Each generator plugin defaults output.barrel to { type: 'named' }; the root output.barrel on defineConfig defaults to false.
output.banner
Text added to the top of every generated file, such as a license header or @ts-nocheck directive. Pass a string, or a function (meta: BannerMeta) => string that receives the document info (title, description, version, baseURL) and per-file context (filePath, baseName, isBarrel, isAggregation), so a directive can skip barrel files.
output.footer
Text added to the bottom of every generated file (string or (meta: BannerMeta) => string), like banner but for closing comments. Pair banner: '/* eslint-disable */' with footer: '/* eslint-enable */' to scope a lint disable to the generated file.
group
Switch the mode to see where these operations land on disk.
clients/pet/- getPetById
- addPet
clients/store/- getInventory
clients/order/- placeOrder
- getOrderById
clients/user/- loginUser
group: { type: "tag" } splits the output by the operation tag, so placeOrder follows its order tag.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. It applies only to output.mode: 'directory'.
IMPORTANT
Combining group with output.mode: 'file' stops the build with a KUBB_INVALID_PLUGIN_OPTIONS error.
group.type
Property used to assign each operation to a group ('tag' | 'path'), required whenever group is set. An operation with no tag goes in the default group.
'tag'uses the operation's first tag.'path'uses the first URL segment, such aspetfor/pet/{petId}.
group.name
Turns a group key into a folder or identifier name, used as the subdirectory name and as a suffix on aggregate files. Type (context: { group: string }) => string, default ({ group }) => camelCase(group), which for type: 'path' groups uses the first URL segment as-is instead of camelCasing.
enum
How OpenAPI enums are represented in the generated TypeScript, and how their names are cased.
enum.type
Representation of each enum. Defaults to 'asConst'.
'asConst'emits anas constobject plus a key/value type. Tree-shakeable, with no runtime.'enum'emits a TypeScriptenumwith JavaScript runtime code.'constEnum'emits aconst enum, inlined at compile time and incompatible with--isolatedModules.'literal'emits a union type with no runtime value.'inlineLiteral'inlines the union at each usage site instead of giving it a name.
export const petStatus = {
available: 'available',
pending: 'pending',
sold: 'sold',
} as const
export type PetStatusKey = (typeof petStatus)[keyof typeof petStatus]export enum PetStatus {
available = 'available',
pending = 'pending',
sold = 'sold',
}export const enum PetStatus {
available = 'available',
pending = 'pending',
sold = 'sold',
}export type PetStatus = 'available' | 'pending' | 'sold'export type PetStatus = 'available' | 'pending' | 'sold'enum.constCasing
Casing of the generated const variable when type is 'asConst'. Defaults to 'camelCase'.
'camelCase'names the constpetStatus.'pascalCase'names the constPetStatus, matching the schema name.
export const petStatus = {
available: 'available',
pending: 'pending',
sold: 'sold',
} as const
export type PetStatusKey = (typeof petStatus)[keyof typeof petStatus]export const PetStatus = {
available: 'available',
pending: 'pending',
sold: 'sold',
} as const
export type PetStatusKey = (typeof PetStatus)[keyof typeof PetStatus]enum.typeSuffix
Suffix on the type alias generated when type is 'asConst' (string, default 'Key'), applied only to the companion type alias, not the const object name. Set it to '' to drop the suffix, which with constCasing: 'pascalCase' merges the const and type under one name.
export const petStatus = {
available: 'available',
pending: 'pending',
sold: 'sold',
} as const
export type PetStatusKey = (typeof petStatus)[keyof typeof petStatus]export const petStatus = {
available: 'available',
pending: 'pending',
sold: 'sold',
} as const
export type PetStatusValue = (typeof petStatus)[keyof typeof petStatus]export const petStatus = {
available: 'available',
pending: 'pending',
sold: 'sold',
} as const
export type PetStatus = (typeof petStatus)[keyof typeof petStatus]enum.keyCasing
Casing applied to enum key names, 'none' by default (the raw value from the spec).
| Value | Example key |
|---|---|
'screamingSnakeCase' | ENUM_VALUE |
'snakeCase' | enum_value |
'pascalCase' | EnumValue |
'camelCase' | enumValue |
'none' (default) | as-is |
syntaxType
Whether object schemas are emitted as type aliases or interface declarations, with type as the safer default. Pick interface only when consumers need declaration merging, which is rare for generated code and covered in Type vs Interface.
export type Pet = {
name: string
}export interface Pet {
name: string
}optionalType
How optional properties are written. Defaults to 'questionToken'.
'questionToken'writestype?: string, so the property may be missing.'undefined'writestype: string | undefined, so it must exist but may beundefined.'questionTokenAndUndefined'writestype?: string | undefined, the strictest form. Use it with"exactOptionalPropertyTypes": true.
export type Pet = {
type?: string
}export type Pet = {
type: string | undefined
}export type Pet = {
type?: string | undefined
}arrayType
Syntax for array types. Defaults to 'array'.
'array'uses the postfixType[].'generic'usesArray<Type>, which reads better for complex elements likeArray<{ id: number }>.
export type Pet = {
tags: string[]
}export type Pet = {
tags: Array<string>
}include
Generates only the operations and schemas that match at least one entry, and skips the rest. Each entry filters by tag, operationId, path, method, contentType, or schemaName, with a pattern that can be a string or a RegExp, both matched as a regular expression against the value. A string pattern is compiled with new RegExp(pattern), so it is not an exact match: pattern: 'pet' also matches 'petType' or 'superpet'.
export type Include = {
type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType' | 'schemaName'
pattern: string | RegExp
}exclude
Skips any operation or schema that matches at least one entry, the opposite of include. Entries use the same type and pattern fields as include, and when both options match an item, exclude wins.
override
Applies different plugin options to operations that match a pattern. 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. The first matching entry merges onto the plugin defaults, and later entries do not stack.
export type Override = {
type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType' | 'schemaName'
pattern: string | RegExp
options: Omit<Partial<Options>, 'override'>
}resolver
Changes how the plugin names generated files and symbols. Pass a partial patch. Override only the members you want, and anything you omit keeps resolverTs. See Override a resolver for the this context and how a patch layers over the default.
TIP
Inside a method this is the full resolver, so this.default.name(name) reuses the built-in casing.
type ResolverTsPatch = {
name?(name: string): string
file?: {
baseName?(params: { name: string; extname: string }): string
path?(params: { baseName: string; output: Output }): string
}
param?: {
name?(node: OperationNode, param: ParameterNode): string // → 'DeletePetPathPetId'
path?(node: OperationNode, param: ParameterNode): string // → 'GetPetByIdPath'
query?(node: OperationNode, param: ParameterNode): string // → 'FindPetsByStatusQuery'
headers?(node: OperationNode, param: ParameterNode): string // → 'DeletePetHeaders'
}
response?: {
status?(node: OperationNode, statusCode: StatusCode): string // → 'ListPetsStatus200'
options?(node: OperationNode): string // → 'ListPetsOptions'
responses?(node: OperationNode): string // → 'ListPetsResponses'
response?(node: OperationNode): string // → 'ListPetsResponse'
body?(node: OperationNode): string // → 'CreatePetBody'
}
enum?: {
keyName?(node: { name?: string | null }, enumTypeSuffix?: string): string // → 'PetStatusKey'
}
}macros
Rewrites AST nodes before they are printed, without forking the generator. Each macro callback (such as schema or operation) receives the node and a context object, and returns a replacement or undefined to leave it as is. Omitted callbacks keep their defaults, and macros run in order, so a later one sees the output of an earlier one.
printer
Replaces the node handler for a schema type such as 'integer' or 'date' with one that builds its TypeScript AST node. Use this.transform to recurse into nested nodes and this.options to read printer options. The printer guide covers the handler context and how overrides compose with macros.
import ts from 'typescript'
import { pluginTs } from '@kubb/plugin-ts'
pluginTs({
printer: {
nodes: {
date() {
return ts.factory.createTypeReferenceNode('Date', [])
},
integer() {
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BigIntKeyword)
},
},
},
})