Dosu LogoDosu Logo
Ask
Join our Discord
Kubb's SpacePublic
Kubb
DocumentsKubb's Space
OpenAPI Schema Conversion
OpenAPI Schema Conversion
Type
Topic
Status
Published
Created
Jul 24, 2026
Updated
Jul 24, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

OpenAPI Schema Conversion#

Kubb's adapter-oas package converts OpenAPI/JSON Schema objects into a language-neutral AST before any code generator runs. The conversion is a multi-step pipeline: a rule table selects the right converter, converter functions build AST nodes, format-mapping constants translate OAS format strings to Kubb schema types, and a rich set of AST node types preserves semantic meaning for downstream generators.


Architecture Overview#

OAS SchemaObject
      │
      ▼
schemaRules (ordered rule table) ← parseSchema.ts
      │ first matching rule wins
      ▼
converter function (scalar / structural / composition)
      │ produces
      ▼
ast.SchemaNode (one of ~15 typed variants)
      │
      ▼
downstream plugin (plugin-ts, plugin-zod, …)

The rule table, converter modules, and AST node types are each in a different package; the constants file ties them together.


1. Rule Table — parseSchema.ts#

schemaRules is an ordered Array<SchemaRule> where each entry has a match predicate and a convert function. The first rule whose match returns true wins; no fall-through occurs.

Priority order :

  1. $ref → convertRef
  2. allOf → convertAllOf
  3. oneOf / anyOf → convertUnion
  4. const → convertConst
  5. format (handled or date-ish with dateType !== false) → convertFormat
  6. Binary (contentMediaType: application/octet-stream) → convertBinary
  7. OAS 3.1 multi-type array → convertMultiType
  8. Implicit string (has minLength/maxLength/pattern but no type) → convertString
  9. Implicit number (has minimum/maximum but no type) → convertNumeric
  10. enum → convertEnum
  11. Object / properties → convertObject
  12. prefixItems → convertTuple
  13. Array → convertArray
  14. Explicit type: 'string' | 'number' | 'integer' | 'boolean' | 'null'

Each converter receives a ConvertContext , which combines the pre-computed SchemaContext (normalized type, options, defaults) with ConverterDeps (a ParseFn for recursion, the document, and the $ref service).


2. Converter Functions#

Converters live in three files under packages/adapter-oas/src/emit/converters/:

FileHandles
scalar.tsstring, number, integer, boolean, null, const, enum, format, blob
structural.tsobject, array, tuple
composition.ts$ref, allOf, oneOf/anyOf, multi-type

The key format converter is convertFormat, which handles three classes:

  • int64 → bigint or integer depending on options.integerType
  • Date/time (date-time, date, time) → dispatches to getDateType, which honors options.dateType to produce datetime, date, or time nodes with offset/local/representation flags
  • Everything else → looks up formatMap via getSchemaType, then emits a typed node; url, uuid, and email also carry min/max length from minLength/maxLength

3. Format Mapping — constants.ts#

formatMap is the static lookup table from OAS format strings to Kubb SchemaType values. It only lists formats whose AST type differs from the raw OAS type:

OAS formatKubb SchemaType
uuiduuid
email, idn-emailemail
uri, uri-reference, urlurl
hostname, idn-hostnameurl
ipv4ipv4
ipv6ipv6
binary, byteblob
int32integer
float, doublenumber

Formats that require runtime option awareness (int64, date-time, date, time) are not in formatMap; they are listed separately in specialCasedFormats and handled directly in convertFormat.

isHandledFormat gates the format rule in schemaRules: it returns true for any formatMap entry or any specialCasedFormat. Formats not in either set fall back to the base type, and the parser emits a KUBB_UNSUPPORTED_FORMAT diagnostic.


4. AST Node Types — packages/ast/src/nodes/schema.ts#

The full SchemaType union has three layers:

  • PrimitiveSchemaType — string, number, integer, bigint, boolean, null, any, unknown, void, never, object, array, date
  • ComplexSchemaType — tuple, union, intersection, enum
  • SpecialSchemaType — ref, datetime, time, uuid, email, url, ipv4, ipv6, blob

Dedicated semantic node types for string formats :

TypeNodeExtra fields
uuidFormatStringSchemaNodemin?, max?
emailFormatStringSchemaNodemin?, max?
urlUrlSchemaNodepath?, min?, max?
ipv4Ipv4SchemaNode—
ipv6Ipv6SchemaNode—

The SchemaNodeBase shared by all nodes stores primitive — the underlying JavaScript primitive type (e.g., uuid nodes carry primitive: 'string') — enabling generators to fall back gracefully when they don't support a given special type .

The factory function createSchema is the single entry point for constructing any SchemaNode. It automatically fills primitive from the TYPE_TO_PRIMITIVE map .


5. Parser Options & Defaults#

DEFAULT_PARSER_OPTIONS provides the baseline ast.ParserOptions:

OptionDefaultControls
dateType'string'How date-time/date/time formats are emitted
integerType'bigint'Whether int64 becomes bigint or integer
unknownType'any'AST type for unrecognized schemas
emptySchemaType'any'AST type for empty {} schemas
enumSuffix'enum'Suffix on derived enum names

These defaults are applied in parser.ts and adapter.ts when callers don't supply explicit options.


Key Files#

PathRole
packages/adapter-oas/src/emit/parseSchema.tsschemaRules table, SchemaRule/ConvertContext types
packages/adapter-oas/src/emit/converters/scalar.tsScalar/format/enum/const converters
packages/adapter-oas/src/emit/converters/composition.tsRef/allOf/union converters
packages/adapter-oas/src/emit/converters/structural.tsObject/array/tuple converters
packages/adapter-oas/src/emit/schemaShape.tsgetSchemaType, isHandledFormat, getDateType, flattenSchema
packages/adapter-oas/src/constants.tsformatMap, specialCasedFormats, DEFAULT_PARSER_OPTIONS
packages/ast/src/nodes/schema.tsAll SchemaNode types, createSchema factory
Documents
Axios Plugin
a-working-mcp-server-from-a-spec
base-url
basic-usage
build-a-url-without-sending
calling-operations
choose-the-client-when-two-are-registered
class-based-sdk
claude-mcp-plugin
comparison
ecosystem
generate
generators
index
index
installation
introduction
kubb-invalid-plugin-options
kubb-plugin-failed
migration
nuxt
options
options
parsers
plugin-client
plugin-cypress
plugin-mcp
plugins
point-at-an-env-driven-host
point-at-an-env-driven-host
query-errors-transport
README
recipes
register-handlers-with-a-server
rspack
serialization
serialization
stream-server-sent-events
transport
typed-request-helpers-against-staging
v5
validate-every-api-response
validate-requests-and-responses
validate-requests-and-responses
OpenAPI Schema Conversion
a-working-mcp-server-from-a-spec
adapter-oas
adapters
ast
calling-operations
calling-operations
changelog
class-based-sdk
claude
claude-code-plugin
claude-mcp-plugin
coerce-query-and-form-input
comparison
contributing
downgrade-int64-to-a-plain-number
ecosystem
encode-a-custom-type-on-requests
faq
format-date-fields-with-dayjs
generate
generators
How can you extend Kubb's generated code to access OpenAPI security schemes inside fetch functions, so each generated client knows which security scheme it requires?
index
index
index
index
index
index
index
index
introduction
kubb-adapter-required
kubb-deprecated
kubb-invalid-document
kubb-invalid-server-variable
kubb-plugin-failed
kubb-ref-not-found
kubb-unsupported-format
map-spec-types-to-native-ts
migration
nuxt
options
parsers
plugin-mcp
plugin-ts
plugin-zod
plugins
prefix-every-schema-type-name
printers
README
recipes
rspack
serialization
serialization
serialization
tree-shakeable-enums
v3
v5
Package Version Management
init
kubb-plugin-failed
kubb-update-available
migration
nuxt
parsers
rspack
AGENTS
CLAUDE
CONTRIBUTING
GEMINI
SKILL
SKILL
What new feature was proposed and implemented for the `kubb-cli` tool regarding OpenAPI/Swagger file validation?
a-barrel-in-every-folder
adapters
architecture
ast
astro
authentication
authentication
authentication
auto-generated-mock-data
barrel
barrel-files
base-url
base-url
build-a-url-without-sending
calling-operations
calling-operations
calling-operations
configuration
copilot-instructions
creating-plugins
custom-query-keys
custom-query-keys
deterministic-data-with-a-seed
diagnostics
diagnostics
engine
error-handling
error-handling
error-handling
esbuild
exclude
farm
generators
grouping
handlers-you-fill-from-tests
hooks
immutable-requests
include
index
index
index
index
index
index
index
index
infinite-scroll-query
infinite-scroll-query
interceptors
interceptors
interceptors
jsx
kit
kit
kubb-clean-root
kubb-format-failed
kubb-input-not-found
kubb-input-request-failed
kubb-input-required
kubb-input-unreachable
kubb-legacy-input
kubb-lint-failed
kubb-path-traversal
kubb-performance
kubb-plugin-info
kubb-plugin-not-found
kubb-plugin-warning
kubb-post-generate-failed
kubb-unknown
llmstxt
localized-mock-data
macros
macros
macros-option
markdown
mcp
mcp
named-re-exports-for-tree-shaking
one-wildcard-barrel
options
options
options
options
options
options
options
options
options
options
options
options
options
output-banner
output-footer
override
parsers
plain-language
plugin-faker
plugin-msw
plugin-react-query
plugin-swr
plugin-vue-query
plugins
prefix-every-generated-type-name
printers
pull_request_template
reactive-params-that-refetch
renderers
renderers
resolvers
resolvers
resolvers
resolvers
rolldown
rollup
security
server-sent-events
server-sent-events
skip-a-request-until-ready
standalone-api-docs-page
storage
storage
strip-descriptions-with-a-macro
strip-descriptions-with-a-macro
suspense-hooks
telemetry
testing
transport
transport
tree-shakeable-schemas-with-zod-mini
turn-barrels-on
usa-english
v4
validate
vite
webpack
wrap-hooks-with-shared-options
zod-as-the-single-source-of-truth