Skip to content

Compatibility report ​

openapi-typesafe promises the same output as openapi-typescript 7.13, except where the output is a bug. This page shows how that is checked and what the last run found. CI runs the full corpus every night; this page is refreshed from that run for every release candidate and every major or minor release, and the GitHub release notes link it.

Result (2026-11-04): 50,960 cases, 0 unexpected differences. 99.99% of the outputs are the same byte for byte, and 100% have the same types.

What is compared ​

  • Golden output: openapi-typescript at commit d46a319a (tag fork-base), the code of the 7.13.0 release. A separate run of 4,600 cases found it gives the same bytes as the published openapi-typescript@7.13.0 on every document both can load.
  • Candidate: the current openapi-typesafe generator.
  • Corpus: 1,820 OpenAPI 3.x documents: the APIs.guru directory plus 20 curated ones (the large GitHub, Stripe, OpenAI, Cloudflare, Twilio and Kubernetes APIs and the official OpenAPI examples, including 3.2). Each one is pinned by its SHA-256 hash.
  • Options: 28 option sets: the defaults, every boolean flag on its own and the combinations that interact (--enum with --enum-values, --root-types with its naming flags, and others). 1,820 × 28 = 50,960 cases.

For every case the tool generates the types with both generators and compares them in three steps:

  1. Bytes. The files are compared as text. The header line that names the generator is ignored.
  2. Types. If the bytes differ, each exported type is checked with a strict identity check: two types count as equal only if TypeScript sees them as identical, so readonly and any are not ignored.
  3. Compiles. If the golden output itself does not compile, both outputs are type-checked with strict settings and the error counts are compared.

Summary ​

ResultCasesWhat it means
Same bytes49,794The output is the same file.
Same types4--enum-values constants whose golden names start with a digit (not valid JavaScript) get a value prefix; every exported type is equal.
Different0—
Golden output does not compile994openapi-typescript 7.13 writes TypeScript with errors; ours has no more errors, and 766 of these compile without any (see below).
Golden generator fails168openapi-typescript 7.13 stops with an error on 6 documents (see below).
Candidate fails0—

The rates count only cases where the golden output exists and compiles (49,798 cases): byte identity 99.99%, type identity 100%, and 100% of the golden types are kept.

Documents the golden generator cannot load ​

These 6 documents fail in every option set (6 × 28 = 168 cases):

  • 3 are OpenAPI 3.2 documents. The golden generator rejects 3.2; openapi-typesafe loads them and types the 3.2 features as well.
  • 3 point to files or URLs that cannot be downloaded (a relative $ref outside the document, and a URL that returns HTTP 400). Both generators stop on them.

Golden output that does not compile ​

These cases are not compared type by type: the golden file has TypeScript errors, so the check is that ours has no more. They come from option combinations whose original output does not compile:

Option setCasesOurs compilesCause
--path-params-as-types791600A path template such as `/apps/${string}` also matches another path whose type does not fit; ours writes such templates in an intersection where the error is sure (see the CLI docs).
--make-paths-enum8178Paths that map to the same member name.
--enum (with --enum-values, --dedupe-enums, --conditional-enums)10877Enum members whose names collide, which ours numbers, and names that start with a digit.
--exclude-deprecated1311A kept schema points to a deprecated one, which ours keeps.
--root-types-keep-casing10A schema name that is not a valid identifier.

Where ours still has errors, it has no more than the golden output. In 2 of the 791 cases (Microsoft Graph and Graph beta with --path-params-as-types, 24 MB each) TypeScript cannot finish the check of either file: it stops with RangeError: Map maximum size exceeded, as a user's tsc does; the default output of the same documents compiles.

Intentional differences ​

Each change below fixes a bug and has a test and a changelog entry. Before comparing, the tool applies the same change to the golden output, so a case that differs only by these counts as the same. The table lists how many cases each change touched.

ChangeFixesCases
--enum: an empty string value gets the member name "" instead of none#2807, #281293
--enum-values: FlattenedDeepRequired flattens readonly arrays and nullable parents#2714, #27371,527
--enum-values: the ReadonlyArray helper accepts readonly arrays#27491,527
--read-write-markers: Readable / Writable keep primitives, arrays, tuples and null-only keys#2615, #2620, #2632, #2717, #27653,628
--enum: a name that starts with a digit gets the Value prefixthe golden output does not compile12
--root-types-keep-casing: characters that cannot be in an identifier become _the golden output does not compile151
--root-types-no-schema-prefix: a schema name that starts with a digit keeps its prefixthe golden output does not compile8

The migration guide lists every change from openapi-typescript 7.13, including the ones this corpus does not reach.

Real projects ​

22 open-source projects that use openapi-typescript or openapi-fetch were checked out at a fixed commit and run as they are, then again after switching to openapi-typesafe by package name only. All 22 pass every step they had passed before (install, build, type check, tests, whatever the project has), and all 18 files they generate are the same as before.

ProjectCommit
unsplash-jsde61b942e16a
swr-openapi34d1e0dbb524
openapi-fetch-gen1b2ec9ee05d2
vc-bots0bfc54accbe4
org-roam-ui-litee036f5ee0a6f
acai-cli6ec9df89dda3
obsidian-media-db81ff85560f2a
immich-discord-bota0369c113426
lichess-broadcastere5a309199251
arena-cli63441ef27f72
whatsapp-js-sdk240843d66159
permit-cli745e8a3dc656
miro-codef2226a240c56
immerle-uic715fb9f062c
vue-h5-templatea829261c3558
coderabbit-bitbucketc39a1e9c37e7
vitrina-apiad69f0078de7
rootly-tsdece1e2322e8
ai-dial-sdk1b23ddf8c449
sendly-js49a9c06140d7
forge-dashboard-sdke1f00f9d8e9a
openapi-axios4fc0ddec4eed

Versioning ​

From 1.0.0 the packages follow semantic versioning, and all five always have the same version. The full rule is ADR-034.

Stable in 1.x. A minor or patch release does not remove, rename or narrow:

  • the package entry points (import … from "openapi-typesafe" and the same for the other packages), their exported names and documented types, and the openapi-typesafe and openapi-typesafe-migrate commands;
  • the CLI flags, the x-openapi-ts settings in redocly.yaml, the Node API options and their defaults;
  • the error codes and exit codes, the warning codes, the deprecation codes and the fix names: a code keeps its meaning;
  • the generated types: the same document with the same options gives the same exported types. A change to output that compiles is an opt-in fix; output that does not compile can be fixed in any release.

What a minor release may add. New exports, options, flags, error, warning and deprecation codes, fix names (fix: ["all"] then includes the new fix), IR node kinds, members of exported unions such as ErrorCode, WarningCode, OutputFix, IrType and HttpMethod, and optional fields. So:

  • give a switch over a code or a kind a default branch;
  • return an IR node of a kind you do not know unchanged;
  • do not treat ERROR_CODES, WARNING_CODES or OUTPUT_FIXES as a complete list.

Not covered. These may change in any release:

  • deep imports such as openapi-typesafe/dist/… or openapi-typesafe/src/…; they keep resolving where openapi-typescript had the same file, but are not part of the API;
  • the text of messages, warnings and notices (match on the code), and the CLI's decorated output;
  • the keys of an error's details, except those the Node API docs list;
  • log formats (DEBUG=openapi-ts:* lines, the migration tool's --log file) and the generated header comment;
  • exports, fields and members marked @internal, and the generator's own state on options.ctx;
  • the shape of the types generated for the OpenAPI 3.2 additions (query operations, additionalOperations, itemSchema, in: querystring, components.mediaTypes), which is experimental in 1.x. A change is named in the changelog.

Node.js and TypeScript. A minor release may raise the lowest supported Node.js version, only to drop a line that has reached its end of life (Node.js 22 on 2027-04-30), and its changelog says so. The lowest TypeScript version for type-checking the output and the clients (5.4) rises only in a major release.

Deprecations. Nothing is removed before the next major version. A deprecated export is marked @deprecated in the types, so editors strike it through, and the docs say what to use instead. Where a deprecation also warns at run time, it is a Node.js DeprecationWarning with an OPENAPI_TYPESAFE_DEP_* code (Deprecations).

Run it yourself ​

The comparison tool lives in tools/compat-harness. Its README explains how to download the corpus, build both generators and produce this report. CI runs it on a 200-document subset with the default options for every pull request and push to main, and on the full corpus with all 28 option sets every night.

Released under the MIT License. Built on openapi-typescript, openapi-fetch and openapi-react-query.