How results are checked
There are two layers: a check on every conversion you run, and a test suite that every change to the converters must pass.
On every conversion
Before a result is shown, it goes through a check that does not trust the converter. The result is then labelled with what happened:
- Verified: the check passed and nothing was lost.
- Verified, with notes: the check passed, and some things could not convert exactly (for example, XML has no numbers, or Prisma has no CHECK constraints). Each one is listed.
- Review needed: output was produced, but the check could not confirm it. The reason is shown.
- Could not convert: the input is invalid or unsupported, with the line number when there is one.
What the check is depends on the converter: parsing the output back and comparing values, compiling with the TypeScript compiler, running the generated Zod schema or Pydantic models against the reference JSON Schema validator, reading a Prisma schema back through Prisma's own engine, running a Drizzle schema with drizzle-orm, or asking SQLAlchemy for the SQL it would run and comparing it with yours using the real PostgreSQL parser. Each converter page lists its checks.
Before every release
- Random data. Hundreds of random JSON values per converter, including awkward keys (
__proto__,constructor, spaces, emoji) and strings like"yes","007"and"2026-10-09", must survive every data conversion. - Equivalence for Zod and TypeScript. For each test schema, valid data is generated and then broken in many ways (missing keys, wrong types, extra keys, edge-case strings and numbers). The generated Zod schema and the TypeScript validation functions (validate.ts) must each agree with Ajv, the reference validator, on every value, and every value they accept must type-check against the generated TypeScript.
- A real Postgres database. Every SQL test schema is executed in Postgres. What Postgres actually created is then compared with the Prisma output, column by column, key by key and relation by relation.
- Known differences are locked in. Where validators legitimately disagree (for example on unusual email addresses), the exact list of differences is part of the test suite, so a new difference fails the build.
The test suite currently has 595 tests and runs on every change.
Real-world schemas
The JSON Schema converters are also run against 990 real schemas from SchemaStore (tsconfig, package.json, GitHub Actions, Docker Compose, Kubernetes and many more), checked in October 2026. Structure is compared with format checks off, since validators differ on formats by design.
| TypeScript output that compiles and verifies | 990 / 990 (100.0%) |
|---|---|
| Zod output that runs and verifies | 989 / 990 (99.9%) |
| Schemas where Zod agreed with Ajv on every generated value | 887 / 889 (99.8%) |
| Remaining disagreements that come with a warning naming the cause | 2 / 2 |
For the remaining 101 schemas the test-data generator could not produce valid samples (usually very large or highly recursive schemas), so only the conversion checks were run. The two disagreements both come from unevaluatedProperties, which is not translated yet and is named in the result's warnings.
Real-world API specs
The OpenAPI converters are run against 165 real API descriptions from the APIs.guru directory (GitHub, Stripe, Slack, Twilio, Azure, Google and others): 27,979 schemas in all, checked in October 2026.
| Specs with schemas whose TypeScript output (types + validate.ts) verifies | 161 / 161 |
|---|---|
| Specs with schemas whose Zod output verifies | 158 / 161 |
| Schemas tested for equivalence with Ajv, and disagreements found | 1,377 tested, 0 disagreements |
4 specs have no schemas at all (and are reported as such); for the other 3, the test run ran out of time on very large documents.
Pydantic, on real schemas
The same 990 SchemaStore schemas are converted to Pydantic models, which are then run with the real pydantic (CPython in WebAssembly) and compared with Ajv on generated valid data and hundreds of broken variants of it. Checked in October 2026.
| Models that load and verify | 978 / 990 (98.8%) |
|---|---|
| … of which with no notes at all (every rule written as pydantic code) | 386 |
| Schemas where pydantic agreed with Ajv on every value, apart from differences named in the notes | 978 / 982 (99.6%) |
| … of which with no difference at all | 846 |
Pydantic has no setting for some JSON Schema rules: oneOf, if/then/else, not, dependencies and contains are checked by small validators in the generated module, and optional fields reject null as JSON Schema does. A few rules still can't be checked (for example patternProperties). Those differences are always named in the result, and when comparing, only those exact rules are relaxed, at the places named. Of the 4 schemas marked "review needed", three are Renovate's config schemas, whose models are nested too deeply for Python's default recursion limit, and one refers to itself in a loop that no validator can check (the result says so). For 8 very large schemas, the test-data generator ran out of time or memory; their conversions still verify or report as above.
Databases
- Prisma → PostgreSQL is compared character for character with what
prisma migratewrites, using Prisma's own migration engine, on 38 schemas (plus every SQL test schema converted to Prisma and back). Each result is also run in a real Postgres. - PostgreSQL → Drizzle and → SQLAlchemy: for each of the 12 SQL test schemas, drizzle-kit and SQLAlchemy turn the generated code back into SQL, which is run in a real Postgres. The resulting database must be identical to the original: columns, types, keys, constraint names, indexes, checks and defaults.
What's not converted yet
A few rarely used JSON Schema keywords (unevaluatedProperties, unevaluatedItems, $dynamicRef) are not translated yet, and TypeScript types cannot express logic keywords such as not or if/then/else (the Zod converter checks them). When your schema uses one of these, the result names it. Nothing is dropped silently.