{
  "id": "kubb-labs/plugin-ts",
  "kind": "plugin",
  "type": "official",
  "artifact": {
    "kind": "npm",
    "package": "@kubb/plugin-ts",
    "version": "5.0.9"
  },
  "repository": {
    "url": "https://github.com/kubb-labs/plugins/tree/main/packages/plugin-ts"
  },
  "manifest": {
    "$schema": "https://kubb.dev/schemas/kubb-extension.json",
    "kind": "plugin",
    "name": "plugin-ts",
    "export": "pluginTs",
    "displayName": "TypeScript",
    "description": "Generates TypeScript types and interfaces from your OpenAPI spec, the typed foundation the other Kubb plugins build on.",
    "category": "types",
    "icon": {
      "light": "https://kubb.dev/feature/typescript.svg"
    },
    "tags": [
      "typescript",
      "types",
      "interfaces",
      "codegen",
      "openapi"
    ],
    "docs": "https://kubb.dev/extensions/kubb-labs/plugin-ts",
    "maintainers": [
      {
        "name": "Stijn Van Hulle",
        "github": "stijnvanhulle"
      }
    ],
    "compatibility": {
      "kubb": ">=5.8.3",
      "node": ">=22"
    },
    "options": [
      {
        "key": "outputPath",
        "path": [
          "output",
          "path"
        ],
        "label": "Output Path",
        "description": "Output folder for generated files",
        "type": "text",
        "default": "types"
      },
      {
        "key": "barrel",
        "path": [
          "output",
          "barrel"
        ],
        "label": "Barrel",
        "description": "How index.ts barrel files are generated",
        "type": "select",
        "default": {
          "type": "named"
        },
        "choices": [
          {
            "label": "named",
            "value": {
              "type": "named"
            }
          },
          {
            "label": "named (nested)",
            "value": {
              "type": "named",
              "nested": true
            }
          },
          {
            "label": "all",
            "value": {
              "type": "all"
            }
          },
          {
            "label": "all (nested)",
            "value": {
              "type": "all",
              "nested": true
            }
          },
          {
            "label": "false (disabled)",
            "value": false
          }
        ]
      },
      {
        "key": "outputMode",
        "path": [
          "output",
          "mode"
        ],
        "label": "Output Mode",
        "description": "How the plugin consolidates its code into files. File mode writes everything into a single file, so the output path must include a file extension and cannot be grouped.",
        "type": "select",
        "default": "directory",
        "choices": [
          {
            "label": "directory (one file per schema)",
            "value": "directory"
          },
          {
            "label": "file (single file)",
            "value": "file"
          }
        ]
      },
      {
        "key": "group",
        "path": [
          "group"
        ],
        "label": "Group",
        "description": "Group generated operations by OpenAPI tag or path",
        "type": "select",
        "default": null,
        "choices": [
          {
            "label": "none",
            "value": null
          },
          {
            "label": "by tag",
            "value": {
              "type": "tag"
            }
          },
          {
            "label": "by path",
            "value": {
              "type": "path"
            }
          }
        ]
      },
      {
        "key": "excludeTags",
        "path": [
          "exclude"
        ],
        "label": "Exclude Tags",
        "description": "Comma-separated OpenAPI tags to exclude from generation",
        "type": "list",
        "item": {
          "type": "tag",
          "pattern": "$item"
        }
      },
      {
        "key": "includeTags",
        "path": [
          "include"
        ],
        "label": "Include Tags",
        "description": "Comma-separated OpenAPI tags to include. Only operations with these tags are generated",
        "type": "list",
        "item": {
          "type": "tag",
          "pattern": "$item"
        }
      },
      {
        "key": "enumType",
        "path": [
          "enum",
          "type"
        ],
        "label": "Enum Type",
        "description": "How OpenAPI enums are represented in the generated TypeScript",
        "type": "select",
        "default": "asConst",
        "choices": [
          {
            "label": "asConst",
            "value": "asConst"
          },
          {
            "label": "enum",
            "value": "enum"
          },
          {
            "label": "constEnum",
            "value": "constEnum"
          },
          {
            "label": "literal",
            "value": "literal"
          },
          {
            "label": "inlineLiteral",
            "value": "inlineLiteral"
          }
        ]
      },
      {
        "key": "enumConstCasing",
        "path": [
          "enum",
          "constCasing"
        ],
        "label": "Enum Const Casing",
        "description": "Casing of the generated const variable (asConst only)",
        "type": "select",
        "default": "camelCase",
        "choices": [
          {
            "label": "camelCase",
            "value": "camelCase"
          },
          {
            "label": "pascalCase",
            "value": "pascalCase"
          }
        ]
      },
      {
        "key": "enumTypeSuffix",
        "path": [
          "enum",
          "typeSuffix"
        ],
        "label": "Enum Type Suffix",
        "description": "Suffix appended to the generated enum type alias (asConst only)",
        "type": "text",
        "default": "Key"
      },
      {
        "key": "enumKeyCasing",
        "path": [
          "enum",
          "keyCasing"
        ],
        "label": "Enum Key Casing",
        "description": "Casing for enum key names",
        "type": "select",
        "default": "none",
        "choices": [
          {
            "label": "none",
            "value": "none"
          },
          {
            "label": "pascalCase",
            "value": "pascalCase"
          },
          {
            "label": "camelCase",
            "value": "camelCase"
          },
          {
            "label": "snakeCase",
            "value": "snakeCase"
          },
          {
            "label": "SCREAMING_SNAKE_CASE",
            "value": "screamingSnakeCase"
          }
        ]
      },
      {
        "key": "syntaxType",
        "path": [
          "syntaxType"
        ],
        "label": "Syntax Type",
        "type": "select",
        "default": "type",
        "choices": [
          {
            "label": "type",
            "value": "type"
          },
          {
            "label": "interface",
            "value": "interface"
          }
        ]
      },
      {
        "key": "optionalType",
        "path": [
          "optionalType"
        ],
        "label": "Optional Type",
        "type": "select",
        "default": "questionToken",
        "choices": [
          {
            "label": "questionToken",
            "value": "questionToken"
          },
          {
            "label": "undefined",
            "value": "undefined"
          },
          {
            "label": "questionTokenAndUndefined",
            "value": "questionTokenAndUndefined"
          }
        ]
      },
      {
        "key": "arrayType",
        "path": [
          "arrayType"
        ],
        "label": "Array Type",
        "type": "select",
        "default": "array",
        "choices": [
          {
            "label": "array (T[])",
            "value": "array"
          },
          {
            "label": "generic (Array<T>)",
            "value": "generic"
          }
        ]
      }
    ]
  },
  "submittedAt": "2026-10-12T20:11:53Z",
  "publishedAt": "2026-10-12T20:11:53Z",
  "reviewedAt": "2026-10-13T12:44:26Z",
  "stats": {
    "downloads": 1250222,
    "weekly": 319879,
    "stars": 8
  },
  "overview": "# TypeScript\n\nGenerates TypeScript types and interfaces from your OpenAPI spec. You get a type for every schema, plus the request, response, and parameter types of each operation.\n\nMost other Kubb plugins build on these types. The client, query, mock, and test plugins import them, so add this plugin first.\n\n## Setup\n\nNo other plugins or packages are needed.\n\n## Options worth knowing\n\n- `enum.type` sets how enums are written: `asConst` (default), `enum`, `constEnum`, `literal`, or `inlineLiteral`. `enum.constCasing`, `enum.typeSuffix`, and `enum.keyCasing` tune the names.\n- `syntaxType` writes object schemas as `type` aliases (default) or `interface` declarations.\n- `optionalType` sets how optional properties are written: `questionToken` (default), `undefined`, or `questionTokenAndUndefined`.\n- `arrayType` writes arrays as `T[]` (default) or `Array<T>`.\n- `group` splits the output into folders by tag or path. It does not work with `output.mode: 'file'`.\n\n## Example\n\n```typescript [kubb.config.ts]\nimport { defineConfig } from 'kubb/config'\nimport { pluginTs } from '@kubb/plugin-ts'\n\nexport default defineConfig({\n  input: './petStore.yaml',\n  output: { path: './src/gen' },\n  plugins: [\n    pluginTs(),\n  ],\n})\n```\n\n## See also\n\n- [TypeScript](https://www.typescriptlang.org/)\n- [TypeScript Compiler API](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API)\n",
  "options": "# Options\n\nPass these options to `pluginTs()`. Shared options link to [Shared plugin options](https://kubb.dev/docs/5.x/reference/plugin-options) for details.\n\n## Options overview\n\n| Option                                                                    | Purpose                                                                | Default                                                                               |\n| ------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |\n| [`output`](https://kubb.dev/docs/5.x/reference/plugin-options#output)     | Where files are written: `path`, `mode`, `barrel`, `banner`, `footer`. | `{ path: 'types', barrel: { type: 'named' } }`                                        |\n| [`group`](https://kubb.dev/docs/5.x/reference/plugin-options#group)       | Split output by tag or path: `type`, `name`.                           | None                                                                                  |\n| [`enum`](#enum)                                                           | How enums are generated and cased.                                     | `{ type: 'asConst', constCasing: 'camelCase', typeSuffix: 'Key', keyCasing: 'none' }` |\n| [`syntaxType`](#syntaxtype)                                               | Emit object schemas as type aliases or interfaces.                     | `'type'`                                                                              |\n| [`optionalType`](#optionaltype)                                           | How optional properties are written.                                   | `'questionToken'`                                                                     |\n| [`arrayType`](#arraytype)                                                 | `Type[]` or `Array<Type>`.                                             | `'array'`                                                                             |\n| [`include`](https://kubb.dev/docs/5.x/reference/plugin-options#include)   | Keep only operations and schemas that match.                           | None                                                                                  |\n| [`exclude`](https://kubb.dev/docs/5.x/reference/plugin-options#exclude)   | Skip operations and schemas that match.                                | `[]`                                                                                  |\n| [`override`](https://kubb.dev/docs/5.x/reference/plugin-options#override) | Apply different options per pattern.                                   | `[]`                                                                                  |\n| [`resolver`](#resolver)                                                   | Customize generated names and file paths.                              | `resolverTs`                                                                          |\n| [`macros`](https://kubb.dev/docs/5.x/reference/plugin-options#macros)     | Rewrite AST nodes before printing.                                     | `[]`                                                                                  |\n| [`printer`](#printer)                                                     | Replace the handler for a schema type.                                 | None                                                                                  |\n\n## Option details\n\n### enum\n\nHow OpenAPI enums are represented in the generated TypeScript, and how their names are cased.\n\n|          |                                                                                       |\n| -------- | ------------------------------------------------------------------------------------- |\n| Type     | `{ type?, constCasing?, typeSuffix?, keyCasing? }`                                    |\n| Required | `false`                                                                               |\n| Default  | `{ type: 'asConst', constCasing: 'camelCase', typeSuffix: 'Key', keyCasing: 'none' }` |\n\n`constCasing` and `typeSuffix` apply only to `type: 'asConst'`. `keyCasing` applies to `'asConst'`, `'enum'` and `'constEnum'`, since the literal modes emit values only.\n\n#### enum.type\n\nRepresentation of each enum.\n\n|          |                                                                      |\n| -------- | -------------------------------------------------------------------- |\n| Type     | `'asConst' \\| 'enum' \\| 'constEnum' \\| 'literal' \\| 'inlineLiteral'` |\n| Required | `false`                                                              |\n| Default  | `'asConst'`                                                          |\n\n::field-group\n\n:::field{name=\"'asConst'\"}\nEmits an `as const` object and a union type of its values. Bundlers drop the object when nothing uses it.\n:::\n\n:::field{name=\"'enum'\"}\nEmits a TypeScript `enum` with JavaScript runtime code.\n:::\n\n:::field{name=\"'constEnum'\"}\nEmits a `const enum`, inlined at compile time and incompatible with `--isolatedModules`.\n:::\n\n:::field{name=\"'literal'\"}\nEmits a named union type with no runtime value.\n:::\n\n:::field{name=\"'inlineLiteral'\"}\nEmits the same union as `'literal'` but inlines it at each usage site instead of naming it.\n:::\n\n::\n\n::code-group\n\n```typescript ['asConst' (default)]\nexport const petStatus = {\n  available: 'available',\n  pending: 'pending',\n  sold: 'sold',\n} as const\n\nexport type PetStatusKey = (typeof petStatus)[keyof typeof petStatus]\n```\n\n```typescript ['enum']\nexport enum PetStatus {\n  available = 'available',\n  pending = 'pending',\n  sold = 'sold',\n}\n```\n\n```typescript ['literal']\nexport type PetStatus = 'available' | 'pending' | 'sold'\n```\n\n::\n\n#### enum.constCasing\n\nCasing of the generated const object when `type` is `'asConst'`.\n\n|          |                               |\n| -------- | ----------------------------- |\n| Type     | `'camelCase' \\| 'pascalCase'` |\n| Required | `false`                       |\n| Default  | `'camelCase'`                 |\n\n::field-group\n\n:::field{name=\"'camelCase'\"}\nNames the const `petStatus`.\n:::\n\n:::field{name=\"'pascalCase'\"}\nNames the const `PetStatus`, matching the schema name.\n:::\n\n::\n\n#### enum.typeSuffix\n\nSuffix on the companion type alias when `type` is `'asConst'`. It never changes the const object name. Set it to `''` to drop the suffix, which with `constCasing: 'pascalCase'` merges the const and the type under one name, `PetStatus`.\n\n|          |          |\n| -------- | -------- |\n| Type     | `string` |\n| Required | `false`  |\n| Default  | `'Key'`  |\n\n```typescript [typeSuffix: 'Value']\nexport type PetStatusValue = (typeof petStatus)[keyof typeof petStatus]\n```\n\n#### enum.keyCasing\n\nCasing applied to enum key names.\n\n|          |                                                                                |\n| -------- | ------------------------------------------------------------------------------ |\n| Type     | `'none' \\| 'camelCase' \\| 'pascalCase' \\| 'snakeCase' \\| 'screamingSnakeCase'` |\n| Required | `false`                                                                        |\n| Default  | `'none'`                                                                       |\n\n::field-group\n\n:::field{name=\"'none'\"}\nKeeps the raw enum value from the spec as the key.\n:::\n\n:::field{name=\"'camelCase'\"}\nFormats keys as `enumValue`.\n:::\n\n:::field{name=\"'pascalCase'\"}\nFormats keys as `EnumValue`.\n:::\n\n:::field{name=\"'snakeCase'\"}\nFormats keys as `enum_value`.\n:::\n\n:::field{name=\"'screamingSnakeCase'\"}\nFormats keys as `ENUM_VALUE`.\n:::\n\n::\n\n### syntaxType\n\nHow object schemas are declared.\n\n|          |                         |\n| -------- | ----------------------- |\n| Type     | `'type' \\| 'interface'` |\n| Required | `false`                 |\n| Default  | `'type'`                |\n\n::field-group\n\n:::field{name=\"'type'\"}\nGenerates type aliases, `export type Pet = { name: string }`.\n:::\n\n:::field{name=\"'interface'\"}\nGenerates interface declarations, `export interface Pet { name: string }`. Use it when consumers need declaration merging. See [Type vs Interface](https://www.totaltypescript.com/type-vs-interface-which-should-you-use).\n:::\n\n::\n\n### optionalType\n\nHow optional properties are written.\n\n|          |                                                                 |\n| -------- | --------------------------------------------------------------- |\n| Type     | `'questionToken' \\| 'undefined' \\| 'questionTokenAndUndefined'` |\n| Required | `false`                                                         |\n| Default  | `'questionToken'`                                               |\n\n::field-group\n\n:::field{name=\"'questionToken'\"}\nWrites `type?: string`, so the property may be missing.\n:::\n\n:::field{name=\"'undefined'\"}\nWrites `type: string | undefined`, so it must exist but may be `undefined`.\n:::\n\n:::field{name=\"'questionTokenAndUndefined'\"}\nWrites `type?: string | undefined`, so the property may be missing or `undefined`. Use it with `\"exactOptionalPropertyTypes\": true`.\n:::\n\n::\n\n### arrayType\n\nSyntax for array types.\n\n|          |                        |\n| -------- | ---------------------- |\n| Type     | `'array' \\| 'generic'` |\n| Required | `false`                |\n| Default  | `'array'`              |\n\n::field-group\n\n:::field{name=\"'array'\"}\nUses the postfix `tags: string[]`.\n:::\n\n:::field{name=\"'generic'\"}\nUses `tags: Array<string>`, which reads better for complex elements like `Array<{ id: number }>`.\n:::\n\n::\n\n### resolver\n\nOverrides generated file and symbol names. Omitted members keep `resolverTs`. The shared members (`name`, `file`, `imports`) and the `this` context are described under [`resolver`](https://kubb.dev/docs/5.x/reference/plugin-options#resolver).\n\n|          |                             |\n| -------- | --------------------------- |\n| Type     | `ResolverPatch<ResolverTs>` |\n| Required | `false`                     |\n\n::code-collapse{name=\"ResolverTs patch members\"}\n\n```typescript [Partial override]\ntype ResolverTsPatch = {\n  // plus the shared name, file, and imports members\n  param?: {\n    name?(node: OperationNode, param: ParameterNode): string    // → 'DeletePetPathPetId'\n    path?(node: OperationNode, param: ParameterNode): string     // → 'GetPetByIdPath'\n    query?(node: OperationNode, param: ParameterNode): string    // → 'FindPetsByStatusQuery'\n    headers?(node: OperationNode, param: ParameterNode): string  // → 'DeletePetHeaders'\n  }\n  response?: {\n    status?(node: OperationNode, statusCode: StatusCode): string // → 'ListPetsStatus200'\n    options?(node: OperationNode): string                        // → 'ListPetsOptions'\n    responses?(node: OperationNode): string                      // → 'ListPetsResponses'\n    response?(node: OperationNode): string                       // → 'ListPetsResponse'\n    body?(node: OperationNode): string                           // → 'CreatePetBody'\n  }\n  enum?: {\n    keyName?(node: { name?: string | null }, enumTypeSuffix?: string): string // → 'PetStatusKey'\n  }\n}\n```\n\n::\n\n### printer\n\nReplaces 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](https://kubb.dev/docs/5.x/how-to/printers) covers the handler context and how overrides compose with macros.\n\n|          |                              |\n| -------- | ---------------------------- |\n| Type     | `{ nodes?: PrinterTsNodes }` |\n| Required | `false`                      |\n\nSee [Map schema types](https://kubb.dev/extensions/kubb-labs/plugin-ts/guides/customization#map-schema-types) for an example.\n",
  "guides": [
    {
      "id": "customization",
      "title": "Customize generated types",
      "description": "Prefix TypeScript names, change schema type output, and remove descriptions.",
      "content": "# Customize generated types\n\nPrefix TypeScript names, change schema type output, and remove descriptions.\n\nStart with the [TypeScript plugin configuration](https://kubb.dev/extensions/kubb-labs/plugin-ts#example). Apply these changes to `pluginTs()` in that configuration.\n\n## Prefix type names\n\nUse `resolverTs.name` to preserve the plugin's PascalCase rule before adding a prefix.\n\n```typescript [kubb.config.ts]\nimport { pluginTs, resolverTs } from '@kubb/plugin-ts'\n\npluginTs({\n  resolver: {\n    name(name) {\n      return 'Api' + resolverTs.name(name)\n    },\n  },\n})\n```\n\nA generated `Pet` becomes `ApiPet`. File names stay unchanged unless you also customize the file resolver.\n\n## Map schema types\n\nReplace [printer handlers](https://kubb.dev/extensions/kubb-labs/plugin-ts/options#printer) with TypeScript AST nodes.\n\n```typescript [kubb.config.ts]\nimport ts from 'typescript'\nimport { pluginTs } from '@kubb/plugin-ts'\n\npluginTs({\n  printer: {\n    nodes: {\n      date() {\n        return ts.factory.createTypeReferenceNode('Date', [])\n      },\n      integer() {\n        return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BigIntKeyword)\n      },\n    },\n  },\n})\n```\n\nThis maps `date` fields to `Date` and `int32` integers to `bigint`. The separate `bigint` handler controls `int64` fields, which already use `bigint` by default. A `date-time` field uses the `datetime` handler.\n\n## Remove descriptions\n\nClear schema descriptions with a [macro](https://kubb.dev/docs/5.x/reference/plugin-options#macros).\n\n```typescript [kubb.config.ts]\nimport { pluginTs } from '@kubb/plugin-ts'\nimport { ast } from 'kubb/kit'\n\nconst dropDescriptions = ast.defineMacro({\n  name: 'drop-descriptions',\n  schema(node) {\n    return 'description' in node && node.description\n      ? { ...node, description: undefined }\n      : undefined\n  },\n})\n\npluginTs({ macros: [dropDescriptions] })\n```\n\nThe generated types omit description JSDoc. The OpenAPI document stays unchanged. The same macro works with `pluginZod`.\n"
    }
  ]
}
