Benchmarks
quicktype rewritten in Rust: the same output, byte for byte, apart from a few fixed bugs. The CLI is up to 89× faster (about 50× on typical files) and uses a fraction of the memory.
- faster per CLI run at most (
--version, start-up alone); about 50× on typical files - 89×
- faster on quicktype's whole test corpus, 11,178 CLI runs
- 48×
- less memory on pokedex.json: 7.1 MiB against 158 MiB
- 22×
- for a user's 3 GB JSON file, where quicktype ran for more than 5 hours
- ~25 s
Measured on Apple M2 Max on November 15, 2026, against quicktype at c39af7d. How · Get the CLI
Every CLI run, 89× to 9.7× faster
One run of the CLI per benchmark: how many times faster quickertype's is, and both times (quicktype → quickertype; medians of 10 runs). On small inputs most of quicktype's time is starting Node.js and loading quicktype (--version alone takes 226 ms); on large ones it is the work itself, which quickertype does 17× faster on the 40 MB input. "Typical files" are the 11 real-world JSON samples here (82 to 606 KB, to TypeScript and to 8 languages): quickertype is 51× faster on the median one.
Start-up
JSON
8 languages
JSON Schema
GraphQL
Several output files
The numbers as a table
| Benchmark | quicktype | quickertype | Faster |
|---|---|---|---|
| --version | 226 ms | 2.56 ms | 89× |
| tiny JSON (77 B) → TypeScript | 246 ms | 2.90 ms | 85× |
| pokedex (82 KB) → TypeScript | 265 ms | 4.06 ms | 65× |
| us-senators (155 KB) → TypeScript | 274 ms | 4.10 ms | 67× |
| misc/1b409 (606 KB) → TypeScript | 305 ms | 5.51 ms | 55× |
| all 13 samples as one top-level (multi-source) → TypeScript | 354 ms | 11.3 ms | 31× |
| generated (4 MB) → TypeScript | 530 ms | 19.7 ms | 27× |
| generated (40 MB) → TypeScript | 2.79 s | 166 ms | 17× |
| generated (40 MB) → Rust | 2.73 s | 169 ms | 16× |
| github-events (82 KB) → ts | 298 ms | 5.87 ms | 51× |
| github-events (82 KB) → rust | 285 ms | 6.16 ms | 46× |
| github-events (82 KB) → go | 285 ms | 5.39 ms | 53× |
| github-events (82 KB) → cs | 289 ms | 5.33 ms | 54× |
| github-events (82 KB) → java | 303 ms | 7.99 ms | 38× |
| github-events (82 KB) → py | 295 ms | 6.35 ms | 46× |
| github-events (82 KB) → swift | 287 ms | 6.05 ms | 47× |
| github-events (82 KB) → c++ | 300 ms | 7.32 ms | 41× |
| vega-lite.schema (306 KB) → TypeScript | 429 ms | 37.6 ms | 11× |
| vega-lite.schema (306 KB) → C# | 441 ms | 39.9 ms | 11× |
| github.gqlschema (1.2 MB) + query → TypeScript | 253 ms | 8.30 ms | 30× |
| vega-lite.schema → Java (one file per class) | 508 ms | 52.2 ms | 9.7× |
| pokedex → C++ (multi-source) | 276 ms | 4.69 ms | 59× |
Memory
The most memory one run took (peak resident set size). quicktype needs 149 MiB before it reads any input (--version), so on small files it takes 22 times what quickertype does. On the 40 MB input it took 681 MiB against quickertype's 60.8 MiB in this run.
quicktypequickertype
The numbers as a table
| Benchmark | quicktype | quickertype | Less |
|---|---|---|---|
| --version | 149 MiB | 3.5 MiB | 43× |
| pokedex (82 KB) → TypeScript | 158 MiB | 7.1 MiB | 22× |
| vega-lite.schema (306 KB) → TypeScript | 224 MiB | 16.9 MiB | 13× |
| generated (4 MB) → TypeScript | 236 MiB | 16.0 MiB | 15× |
| generated (40 MB) → TypeScript | 681 MiB | 60.8 MiB | 11× |
The whole test corpus, 48× faster
Every step of every case in quicktype's test corpus as this repository records it (tests/golden): 11,178 CLI runs in every output language, from JSON, JSON Schema, GraphQL and TypeScript, 12 at a time.
The numbers as a table
| Engine | Wall time | CLI time, summed | Unexpected exits |
|---|---|---|---|
| quicktype | 494.82 s (8 min 15 s) | 5925.62 s | 0 |
| quickertype | 10.22 s | 110.25 s | 0 |
Big files
quickertype reads JSON as a stream and keeps its tables compact, so files of several gigabytes run in seconds.
Reported by a user, on their own machine; not measured with cargo xtask bench. quicktype's bar is drawn at 5 hours; it ran longer.
| Input | Time | Peak memory | On one thread | quicktype |
|---|---|---|---|---|
| 43.7 MB: the benchmark's generated records, in an object (read in one go) | 157 ms | 60.8 MiB | 155 ms, 60.8 MiB | 2.64 s, 630 MiB |
| 267 MB: an array of 1 million small records: a UUID, a two-value enum, a date and a comment each | 49.9 ms | 21.6 MiB | 260 ms, 6.1 MiB | 5.13 s, 1.43 GiB |
| 2.62 GB: 60 copies of the 40 MB input in one array | 7.33 s | 64.0 MiB | 7.27 s, 63.2 MiB | not timed |
| 2.53 GB: 10.5 million objects with ~210-character strings | 292 ms | 20.2 MiB | 1.31 s, 6.0 MiB | not timed |
657 MB: Scryfall's card data, 120,095 cards in one array (-l ts --just-types -t Cards) | 275 ms | 49.8 MiB | 1.34 s, 20.5 MiB | 28.3 s, 3.19 GiB |
3.01 GB: Scryfall's card data in every language, 551,910 cards in one array (-l ts --just-types -t Cards) | 1.25 s | 142 MiB | 6.21 s, 96.4 MiB | not timed |
Apple M2 Max, 12 cores, 64 GiB, macOS 26.6.2, November 15, 2026, commit 84c638d, load average 2.5 to 4.8: target/release/quickertype <input> -l ts -o <file> (the Scryfall cards with --just-types -t Cards), the runs of each command in turn, after one untimed run (none for quicktype on the 657 MB cards); wall time and peak RSS of each run from wait4, medians of 3 to 15 runs. Time and peak memory are on all cores, the default; on one thread, QUICKTYPE_READ_THREADS=1 reads every sample in one go. quicktype is its CLI on the same input, with the same options. Every command wrote the same output. How each input is made: docs/BENCHMARKS.md, "Large inputs".
In the browser
The playground runs both engines inside the page, so the gap there is smaller. Neither starts a process, and starting Node.js and loading quicktype is most of what a quicktype CLI run on a small file costs (below). What is left is the engine itself, and quickertype's WebAssembly build is still being optimized: natively its engine is 4.0× faster than quicktype's in a warm Node.js process (82.2 ms against 330 ms for 112 runs), and the WebAssembly build does not get all of that yet.
start-up (as long as --version takes)the rest of the run
The numbers as a table
| Engine | Run | Start-up | The rest |
|---|---|---|---|
| quicktype | 265 ms | 226 ms | 39.0 ms |
| quickertype | 4.06 ms | 2.56 ms | 1.51 ms |
Compare both engines in your browser: switch engines in the playground, then Measure warm runs.
Large files in the browser, 17× to 25× faster
The playground reads a JSON array or JSON Lines file of 16 MiB or more on up to 8 Web Workers at once, each with an engine instance of its own, and gives what reading it in one go gives, byte for byte. Here it runs Scryfall's card data (real data), cut to its first cards, against quicktype in the same page, as a user would: the file opened, read and turned into TypeScript. The whole file, 657 MB, is past the longest string a browser holds, so quicktype cannot read it there (the playground says the file is too large for the browser, after 0.51 s: 655,897,953 UTF-16 units of text, against at most 536,870,888 in one string); quickertype runs it in 479 ms warm, at a peak of 920 MiB in the tab.
quicktypequickertype
The numbers as a table
| Input | quicktype: first | warm | tab | quickertype: first | warm | tab | Faster (warm) |
|---|---|---|---|---|---|---|---|
| 100 MB, 18,243 cards | 1.81 s | 1.81 s | 719 MiB | 164 ms | 105 ms | 332 MiB | 17× |
| 250 MB, 45,709 cards | 4.56 s | 4.66 s | 1.95 GiB | 264 ms | 206 ms | 519 MiB | 23× |
| 400 MB, 73,194 cards | 7.31 s | 7.44 s | 2.67 GiB | 343 ms | 308 ms | 681 MiB | 24× |
| 537 MB, 98,375 cards | 9.76 s | 10.2 s | 3.51 GiB | 560 ms | 401 ms | 822 MiB | 25× |
| 657 MB, 120,095 cards | refused | – | – | 533 ms | 479 ms | 920 MiB | quicktype cannot |
Apple M2 Max, 12 cores, 64 GiB, macOS 26.6.2, Chrome 157.0.8103.78, headless, November 15, 2026, commit 84c638d, load average 2.7 to 4.3: the playground with its defaults, TypeScript, top-level Cards: each engine in a fresh headless Chrome per file, the file given to the page as a File, then run as the playground runs a file (its worker reads it and generates the code). Time: from the request to the generated code, as the page sees it. First: the first file run in the tab (after the page's default sample); warm: 3 more runs, each reading the file again (a one-line text in between makes the worker let go of it), the engines interleaved; the median and the best. Tab: the peak physical footprint of the tab's renderer process (the page, its workers, their heaps and WebAssembly memories), sampled every 20 ms, on the first run. The inputs are the first cards of Scryfall's card data, as the file has them; both engines wrote the same output for each.
| Input | In one go: first, warm | In parts: first, warm | Warm × | Memory in one go | In parts: engine + part workers |
|---|---|---|---|---|---|
| 100k records (rulings, generated), 26.8 MB | 67 ms, 43 ms | 45 ms, 18 ms | 2.4× | 72 MiB | 32 MiB + 171 MiB |
| generated cards, 101 MB | 493 ms, 397 ms | 164 ms, 107 ms | 3.7× | 280 MiB | 45 MiB + 245 MiB |
| generated cards, 453 MB | 2.42 s, 2.00 s | 413 ms, 362 ms | 5.5× | 1.08 GiB | 41 MiB + 359 MiB |
| Scryfall cards (real data), 657 MB | 3.14 s, 2.63 s | 528 ms, 501 ms | 5.2× | 1.45 GiB | 32 MiB + 280 MiB |
| Scryfall cards (real data), JSON Lines, 656 MB | 3.10 s, 2.60 s | 525 ms, 496 ms | 5.2× | 1.45 GiB | 32 MiB + 261 MiB |
Apple M2 Max, 12 cores, 64 GiB, macOS 26.6.2, Chrome 157.0.8103.78, headless, November 15, 2026, commit 84c638d, load average 2.5 to 4.7: each input opened in a fresh page (its file chooser) and run to TypeScript with the page's defaults on quickertype's worker: in one go (the test hooks lift the size from which it reads in parts, and the longest text) and in parts on its part workers, the default. First: the request's whole time as the page sees it, reading the file and starting the part workers included. Warm: the median of 5 runs that each read the file again, after one. Memory: the WebAssembly memory of quickertype's engine and of the part workers together, the most each held. Both ways wrote the same output.
Method
- Machine
- Apple M2 Max, 12 cores, 64 GiB, macOS 26.6.2
- Toolchain
- rustc 1.99.1 (58cf8f9c3 2026-10-13), Node.js v24.16.0
- Date
- November 15, 2026
- quicktype
c39af7d, the commit whose output quickertype matches (tests/golden/REFERENCE)- quickertype
84c638d- Command
cargo xtask bench --corpus --in-process --json site/data/benchmarks.json- Runs
- 10 timed runs of each CLI per benchmark after one warm-up run (which also checks that both write the same files); medians of wall time. Peak memory is one more run under
/usr/bin/time. - Load
- load average 4.56 when the run started
Written by cargo xtask bench --json; this note and in_process.results were edited by hand. The load average was 4.6 when the run started and 3.8 to 6.6 while the CLI benchmarks ran; the corpus's TypeScript runs (12 at a time) took it to 174, and it was still falling from 82 to 15 during the in-process benchmark, which gave 363 ms for TypeScript, 110 ms with the system allocator and 81.5 ms with mimalloc. in_process.results are instead the median of three interleaved rounds of the same benchmark right after, at a load average of 3.9 to 4.6 (TypeScript 329 to 333 ms, the system allocator 107 to 108 ms, mimalloc 82.0 to 82.6 ms).
The details, the profile behind each optimization and how to reproduce every number: docs/BENCHMARKS.md. The numbers on this page: benchmarks.json, big-inputs.json, head-to-head.json, and browser-workers.json.
Get the CLI
Its command is quickertype, with quicktype's flags and quicktype's output. With Homebrew (macOS, Linux), npm, or Cargo:
brew install elob/tap/quickertype
npm install -g quickertype
cargo install quickertype
Or the shell installer (macOS, Linux), the PowerShell installer or an MSI (Windows), or an archive from the releases; the README has each one. To use it from JavaScript, the npm package quickertype-core is quicktype-core's API on WebAssembly.