Generate fast, type-safe TypeScript parsers, validators, and type definitions from JSON Schemas.
Warning
mjst is pre-alpha. APIs and generated output will change without notice until 1.0.
mjst is a monorepo of code-generation tools that turn a JSON Schema (Draft 2020-12) into TypeScript:
| Output | Description |
|---|---|
| Parsers | Runtime functions that validate and coerce unknown input into typed values |
| Validators | Lightweight predicate-style validation functions |
| Type definitions | .d.ts types matching the schema, with documentation comments |
| Markdown | Reference docs derived from the schema |
The CLI (mjst) is the primary entry point; the underlying generators are also published as standalone packages.
Most tools in this space pick a single lane — types or validation or docs. mjst generates the whole TypeScript surface from one schema, and it can also consume schemas authored in other libraries as input.
| Types | Validators | Parsers / coercion | Markdown docs | Test data ² | Multi-library input | |
|---|---|---|---|---|---|---|
| mjst | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| json-schema-to-typescript | ✅ | — | — | — | — | — |
| ajv (standalone) | — | ✅ | — | — | — | — |
| quicktype | ✅ | — | 🟡 | — | — | — |
| TypeBox · Zod · Valibot | ✅ | ✅ | ✅ | — | — | n/a ¹ |
✅ first-class · 🟡 partial · — not offered
¹ These libraries are a schema source rather than a competitor — mjst consumes them via @amritk/adapters.
² fast-check arbitraries for property testing plus concrete example values, via @amritk/generate-examples.
mjst's validators are generated TypeScript — straight-line, monomorphic code with no generic dispatch. The exported validateX runs a tiny inlined boolean guard on the happy path and falls back to a separate error-collecting function only when input is actually invalid, so a valid-input check beats every other library measured — including the build-time transformer typia. The numbers below compare a generated mjst validator against typia, an Ajv-compiled function, a TypeBox-compiled checker, and a hand-written Zod schema on the same data.
Each schema also generates a boolean type-guard isX(input): input is X — a single flat predicate (no error array, no cold-path call) returning the same verdict as validateX. It is the inline-friendly equivalent of TypeBox's compiled check / typia's is, for the common "is this valid?" question where you don't need the error list; validateX remains the rich, error-collecting form.
Steady-state throughput (valid input, higher is better):
| schema | mjst (generated) | typia (transformed) | ajv (compiled) | typebox (compiled) | zod |
|---|---|---|---|---|---|
| small (4 fields) | ~22M ops/s | ~4.2M ops/s | ~7.0M ops/s | ~4.0M ops/s | ~1.8M ops/s |
| order (nested + array) | ~6.9M ops/s | ~1.7M ops/s | ~2.5M ops/s | ~1.7M ops/s | ~0.4M ops/s |
| assert-loose | ~110M ops/s | ~100M ops/s | ~31M ops/s | ~41M ops/s | ~3.2M ops/s |
| assert-strict | ~98M ops/s | ~82M ops/s | ~13M ops/s | ~28M ops/s | ~1.1M ops/s |
The assert-loose / assert-strict rows are the exact shape used by moltar/typescript-runtime-type-benchmarks.
Prepare-a-validator cost (one-shot, lower is better):
| mjst (codegen) | ajv (compile) | typebox (compile) | zod | |
|---|---|---|---|---|
| small | ~0.15 ms | ~13 ms | ~0.12 ms | n/a — authored in code |
| order | ~0.20 ms | ~14 ms | ~0.21 ms | n/a — authored in code |
Measured on Bun 1.3 (Linux x64); micro-benchmark figures vary by machine and runtime. Each library is timed in an isolated process over a pool of distinct inputs, reporting the median of many trials (so the optimiser can't hoist or eliminate the work). Every library agrees on each valid/invalid verdict — parity is asserted before timing — and TypeBox is given uuid/email format checkers so every library does the same work. Reproduce with cd packages/generate-validators && bun run bench.
Parsing replicates both parse modes of the same benchmark over the libraries
with a pure (non-mutating) parse operation. parseSafe asserts the types and
strips undeclared keys (zod's .strip()); parseStrict asserts the types
and rejects undeclared keys (zod's .strict()):
| schema | mjst (generated) | zod (.parse) |
typebox (Value.Parse) |
|---|---|---|---|
| parseSafe — strip extras | |||
| small (4 fields) | ~12M ops/s | ~2.5M ops/s | ~1.1M ops/s |
| order (nested + array) | ~5.3M ops/s | ~0.53M ops/s | ~0.14M ops/s |
| assert (moltar shape) | ~12M ops/s | ~3.3M ops/s | ~0.56M ops/s |
| parseStrict — reject extras | |||
| small (4 fields) | ~17M ops/s | ~1.6M ops/s | ~1.5M ops/s |
| order (nested + array) | ~3.4M ops/s | ~0.30M ops/s | ~0.23M ops/s |
| assert (moltar shape) | ~9.4M ops/s | ~1.1M ops/s | ~0.79M ops/s |
mjst parses in strict mode throughout (throwing on a type mismatch like the others), adding stripUnknown for parseSafe and additionalProperties: false for parseStrict; zod uses .object/.strictObject and TypeBox a Clean+Assert/Assert pipeline. Parity — identical parsed output, and rejection of every wrong-typed (and, in strict mode, extra-keyed) sample — is asserted before timing. ajv (removeAdditional) and typia (assertPrune) are excluded because they strip by mutating the input in place rather than returning a new value, which a reused input pool can't measure fairly. Reproduce with cd packages/generate-parsers && bun run bench.
No install required — run it directly with your favourite package runner:
# npm
npx @amritk/mjst --schema ./schema.json --out-dir ./generated
# pnpm
pnpx @amritk/mjst --schema ./schema.json --out-dir ./generated
# yarn
yarn dlx @amritk/mjst --schema ./schema.json --out-dir ./generated
# bun
bunx @amritk/mjst --schema ./schema.json --out-dir ./generatedOr use a config file:
npx @amritk/mjst --config ./mjst.config.jsonTip
If you'd rather add it to a project, install it as a dev dependency:
npm install --save-dev @amritk/mjst # or pnpm add -D / yarn add -D / bun add -dThen use the shorter mjst command in npm scripts or via npx mjst.
See the CLI README for the full flag reference and config file examples.
| Package | Description |
|---|---|
@amritk/mjst |
CLI — generates parsers, validators, and types from a schema |
@amritk/generate-parsers |
Programmatic API for parser + type generation |
@amritk/generate-validators |
Programmatic API for validator generation |
@amritk/runtime-validators |
Runtime JSON Schema validation for schemas not known ahead of time |
@amritk/generate-examples |
Programmatic API for fast-check arbitraries + example data generation |
@amritk/generate-markdown |
Programmatic API for markdown documentation generation |
@amritk/adapters |
Convert schemas from external libraries (TypeBox, Zod, …) into JSON Schema |
@amritk/resolve-refs |
Resolve and inline JSON Schema / OpenAPI $refs, with a default-deny SSRF guard |
@amritk/yaml |
Tiny, dependency-free YAML parser with exact source positions for diagnostics |
@amritk/helpers |
Shared runtime helpers used by generated code |
- Node.js ≥ 20 (or Bun ≥ 1.1) to run the CLI
- TypeScript ≥ 5 in your consuming project
Contributing? You'll need Bun ≥ 1.1 — it's the package manager and bundler for this repo. See CONTRIBUTING.md.
bun install
bun run test # run the test suite
bun run check # lint with biome
bun run build # build all publishable packagesSee .claude/architecture.md for monorepo layout and design notes, and CONTRIBUTING.md for contribution guidelines.