Explanation

Kubb vs orval, HeyAPI, and openapi-typescript

Feature-by-feature comparison of Kubb against orval, HeyAPI, and openapi-typescript.

Kubb, orval, HeyAPI, and openapi-typescript all generate code from OpenAPI specs. The tables compare generated outputs, response handling, and runtime behavior.

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.
FeatureKubborvalHeyAPIopenapi-ts
OpenAPI 2.0, 3.0, 3.1 input✅✅✅🔶1
TypeScript types✅✅✅✅
HTTP client (Axios, Fetch)✅✅✅🔶2
React Query hooks✅✅✅🟡3
Vue Query composables✅✅✅🛑
SWR hooks✅✅✅🟡4
Zod validation schemas✅✅✅5🛑
MSW request handlers✅✅✅🛑
Faker.js mock data✅✅✅🛑
Cypress E2E tests✅🛑🛑🛑
MCP server✅✅🛑🛑
Redoc API documentation✅🛑🛑🛑
Barrel index files✅✅✅🛑

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.
  3. openapi-typescript generates no hooks. React Query support comes from the first-party openapi-react-query runtime, also in maintenance mode.
  4. openapi-typescript relies on the community swr-openapi package.
  5. HeyAPI also generates Valibot schemas alongside Zod.

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.

FeatureKubborvalHeyAPI
Status-discriminated response result✅🔶1🔶2
Multiple success (2xx) responses✅✅✅
Multiple content types per response✅✅🛑3
default and wildcard (4XX, 5XX) responses✅✅4✅
Typed error responses✅🔶5✅
Throw or return the error per call✅🛑✅
Zod v4 schemas tied to the types✅✅✅
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 for the runtime contract.

FeatureKubborvalHeyAPI
Parameter styles from the spec✅🔶1🔶2
Request body serializers (JSON, form-data, urlencoded)✅3✅✅
Pluggable codecs per media type (XML, YAML)✅🛑4🛑4
Runtime body validation✅5🔶5✅5
Server-sent events and streaming✅🔶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.

Extension model

Kubb parses the specification once and shares its AST across plugins. Adapters customize input formats, parsers customize source syntax, and plugins add outputs. Post-enforced plugins handle cross-output work such as barrels. See Architecture and Extension model.

Bundler integrations run generation during builds. The generator MCP server exposes Kubb to AI editors. plugin-mcp instead generates a server for your API.

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.