quickertype

quicktype in Rust

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.

quickertype's CLI, how many times faster than quicktype's

Start-up

  1. --version226 ms → 2.56 ms--version: quickertype 89× faster, 2.56 ms against quicktype's 226 ms89×
  2. tiny JSON (77 B) → TypeScript246 ms → 2.90 mstiny JSON (77 B) → TypeScript: quickertype 85× faster, 2.90 ms against quicktype's 246 ms85×

JSON

  1. pokedex (82 KB) → TypeScript265 ms → 4.06 mspokedex (82 KB) → TypeScript: quickertype 65× faster, 4.06 ms against quicktype's 265 ms65×
  2. us-senators (155 KB) → TypeScript274 ms → 4.10 msus-senators (155 KB) → TypeScript: quickertype 67× faster, 4.10 ms against quicktype's 274 ms67×
  3. misc/1b409 (606 KB) → TypeScript305 ms → 5.51 msmisc/1b409 (606 KB) → TypeScript: quickertype 55× faster, 5.51 ms against quicktype's 305 ms55×
  4. all 13 samples as one top-level (multi-source) → TypeScript354 ms → 11.3 msall 13 samples as one top-level (multi-source) → TypeScript: quickertype 31× faster, 11.3 ms against quicktype's 354 ms31×
  5. generated (4 MB) → TypeScript530 ms → 19.7 msgenerated (4 MB) → TypeScript: quickertype 27× faster, 19.7 ms against quicktype's 530 ms27×
  6. generated (40 MB) → TypeScript2.79 s → 166 msgenerated (40 MB) → TypeScript: quickertype 17× faster, 166 ms against quicktype's 2.79 s17×
  7. generated (40 MB) → Rust2.73 s → 169 msgenerated (40 MB) → Rust: quickertype 16× faster, 169 ms against quicktype's 2.73 s16×

8 languages

  1. github-events (82 KB) → ts298 ms → 5.87 msgithub-events (82 KB) → ts: quickertype 51× faster, 5.87 ms against quicktype's 298 ms51×
  2. github-events (82 KB) → rust285 ms → 6.16 msgithub-events (82 KB) → rust: quickertype 46× faster, 6.16 ms against quicktype's 285 ms46×
  3. github-events (82 KB) → go285 ms → 5.39 msgithub-events (82 KB) → go: quickertype 53× faster, 5.39 ms against quicktype's 285 ms53×
  4. github-events (82 KB) → cs289 ms → 5.33 msgithub-events (82 KB) → cs: quickertype 54× faster, 5.33 ms against quicktype's 289 ms54×
  5. github-events (82 KB) → java303 ms → 7.99 msgithub-events (82 KB) → java: quickertype 38× faster, 7.99 ms against quicktype's 303 ms38×
  6. github-events (82 KB) → py295 ms → 6.35 msgithub-events (82 KB) → py: quickertype 46× faster, 6.35 ms against quicktype's 295 ms46×
  7. github-events (82 KB) → swift287 ms → 6.05 msgithub-events (82 KB) → swift: quickertype 47× faster, 6.05 ms against quicktype's 287 ms47×
  8. github-events (82 KB) → c++300 ms → 7.32 msgithub-events (82 KB) → c++: quickertype 41× faster, 7.32 ms against quicktype's 300 ms41×

JSON Schema

  1. vega-lite.schema (306 KB) → TypeScript429 ms → 37.6 msvega-lite.schema (306 KB) → TypeScript: quickertype 11× faster, 37.6 ms against quicktype's 429 ms11×
  2. vega-lite.schema (306 KB) → C#441 ms → 39.9 msvega-lite.schema (306 KB) → C#: quickertype 11× faster, 39.9 ms against quicktype's 441 ms11×

GraphQL

  1. github.gqlschema (1.2 MB) + query → TypeScript253 ms → 8.30 msgithub.gqlschema (1.2 MB) + query → TypeScript: quickertype 30× faster, 8.30 ms against quicktype's 253 ms30×

Several output files

  1. vega-lite.schema → Java (one file per class)508 ms → 52.2 msvega-lite.schema → Java (one file per class): quickertype 9.7× faster, 52.2 ms against quicktype's 508 ms9.7×
  2. pokedex → C++ (multi-source)276 ms → 4.69 mspokedex → C++ (multi-source): quickertype 59× faster, 4.69 ms against quicktype's 276 ms59×
The numbers as a table
CLI wall time per run, median of 10 runs after one warm-up
BenchmarkquicktypequickertypeFaster
--version226 ms2.56 ms89×
tiny JSON (77 B) → TypeScript246 ms2.90 ms85×
pokedex (82 KB) → TypeScript265 ms4.06 ms65×
us-senators (155 KB) → TypeScript274 ms4.10 ms67×
misc/1b409 (606 KB) → TypeScript305 ms5.51 ms55×
all 13 samples as one top-level (multi-source) → TypeScript354 ms11.3 ms31×
generated (4 MB) → TypeScript530 ms19.7 ms27×
generated (40 MB) → TypeScript2.79 s166 ms17×
generated (40 MB) → Rust2.73 s169 ms16×
github-events (82 KB) → ts298 ms5.87 ms51×
github-events (82 KB) → rust285 ms6.16 ms46×
github-events (82 KB) → go285 ms5.39 ms53×
github-events (82 KB) → cs289 ms5.33 ms54×
github-events (82 KB) → java303 ms7.99 ms38×
github-events (82 KB) → py295 ms6.35 ms46×
github-events (82 KB) → swift287 ms6.05 ms47×
github-events (82 KB) → c++300 ms7.32 ms41×
vega-lite.schema (306 KB) → TypeScript429 ms37.6 ms11×
vega-lite.schema (306 KB) → C#441 ms39.9 ms11×
github.gqlschema (1.2 MB) + query → TypeScript253 ms8.30 ms30×
vega-lite.schema → Java (one file per class)508 ms52.2 ms9.7×
pokedex → C++ (multi-source)276 ms4.69 ms59×

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.

Peak memory of one CLI run

quicktypequickertype

  1. --version43× less--version: quicktype 149 MiB, quickertype 3.5 MiB, 43× less149 MiB3.5 MiB
  2. pokedex (82 KB) → TypeScript22× lesspokedex (82 KB) → TypeScript: quicktype 158 MiB, quickertype 7.1 MiB, 22× less158 MiB7.1 MiB
  3. vega-lite.schema (306 KB) → TypeScript13× lessvega-lite.schema (306 KB) → TypeScript: quicktype 224 MiB, quickertype 16.9 MiB, 13× less224 MiB16.9 MiB
  4. generated (4 MB) → TypeScript15× lessgenerated (4 MB) → TypeScript: quicktype 236 MiB, quickertype 16.0 MiB, 15× less236 MiB16.0 MiB
  5. generated (40 MB) → TypeScript11× lessgenerated (40 MB) → TypeScript: quicktype 681 MiB, quickertype 60.8 MiB, 11× less681 MiB60.8 MiB
The numbers as a table
Peak resident memory of one CLI run
BenchmarkquicktypequickertypeLess
--version149 MiB3.5 MiB43×
pokedex (82 KB) → TypeScript158 MiB7.1 MiB22×
vega-lite.schema (306 KB) → TypeScript224 MiB16.9 MiB13×
generated (4 MB) → TypeScript236 MiB16.0 MiB15×
generated (40 MB) → TypeScript681 MiB60.8 MiB11×

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.

Wall time for all 11,178 runs
  1. quicktypequicktype: 494.82 s (8 min 15 s)494.82 s
  2. quickertypequickertype: 10.22 s10.22 s
The numbers as a table
The golden corpus, every step once
EngineWall timeCLI time, summedUnexpected exits
quicktype494.82 s (8 min 15 s)5925.62 s0
quickertype10.22 s110.25 s0

Big files

quickertype reads JSON as a stream and keeps its tables compact, so files of several gigabytes run in seconds.

A 3 GB JSON file, as a user reported it
  1. quicktypemore than 5 hoursquicktype: more than 5 hours
  2. quickertypeabout 25 squickertype: about 25 s

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.

quickertype on large inputs, measured here
InputTimePeak memoryOn one threadquicktype
43.7 MB: the benchmark's generated records, in an object (read in one go)157 ms60.8 MiB155 ms, 60.8 MiB2.64 s, 630 MiB
267 MB: an array of 1 million small records: a UUID, a two-value enum, a date and a comment each49.9 ms21.6 MiB260 ms, 6.1 MiB5.13 s, 1.43 GiB
2.62 GB: 60 copies of the 40 MB input in one array7.33 s64.0 MiB7.27 s, 63.2 MiBnot timed
2.53 GB: 10.5 million objects with ~210-character strings292 ms20.2 MiB1.31 s, 6.0 MiBnot timed
657 MB: Scryfall's card data, 120,095 cards in one array (-l ts --just-types -t Cards)275 ms49.8 MiB1.34 s, 20.5 MiB28.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 s142 MiB6.21 s, 96.4 MiBnot 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.

One CLI run on pokedex.json (82 KB) → TypeScript

start-up (as long as --version takes)the rest of the run

  1. quicktype265 msquicktype: 265 ms for pokedex.json, of which 226 ms start-up226 ms start-up + 39.0 ms
  2. quickertype4.06 msquickertype: 4.06 ms for pokedex.json, of which 2.56 ms start-up2.56 ms start-up + 1.51 ms
The numbers as a table
One CLI run on pokedex.json: start-up (as long as --version takes) and the rest
EngineRunStart-upThe rest
quicktype265 ms226 ms39.0 ms
quickertype4.06 ms2.56 ms1.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.

Scryfall cards (real data) in the playground: a warm run, quicktype against quickertype

quicktypequickertype

  1. 100 MB, 18,243 cards17× faster100 MB, 18,243 cards: a warm run, quicktype 1.81 s, quickertype 105 ms1.81 s105 ms
  2. 250 MB, 45,709 cards23× faster250 MB, 45,709 cards: a warm run, quicktype 4.66 s, quickertype 206 ms4.66 s206 ms
  3. 400 MB, 73,194 cards24× faster400 MB, 73,194 cards: a warm run, quicktype 7.44 s, quickertype 308 ms7.44 s308 ms
  4. 537 MB, 98,375 cards25× faster537 MB, 98,375 cards: a warm run, quicktype 10.2 s, quickertype 401 ms10.2 s401 ms
The numbers as a table
quicktype and quickertype in the playground: the first run, the warm median, the tab's peak memory
Inputquicktype: firstwarmtabquickertype: firstwarmtabFaster (warm)
100 MB, 18,243 cards1.81 s1.81 s719 MiB164 ms105 ms332 MiB17×
250 MB, 45,709 cards4.56 s4.66 s1.95 GiB264 ms206 ms519 MiB23×
400 MB, 73,194 cards7.31 s7.44 s2.67 GiB343 ms308 ms681 MiB24×
537 MB, 98,375 cards9.76 s10.2 s3.51 GiB560 ms401 ms822 MiB25×
657 MB, 120,095 cardsrefused––533 ms479 ms920 MiBquicktype 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.

quickertype in the playground, reading in one go against in parts on 8 workers
InputIn one go: first, warmIn parts: first, warmWarm ×Memory in one goIn parts: engine + part workers
100k records (rulings, generated), 26.8 MB67 ms, 43 ms45 ms, 18 ms2.4×72 MiB32 MiB + 171 MiB
generated cards, 101 MB493 ms, 397 ms164 ms, 107 ms3.7×280 MiB45 MiB + 245 MiB
generated cards, 453 MB2.42 s, 2.00 s413 ms, 362 ms5.5×1.08 GiB41 MiB + 359 MiB
Scryfall cards (real data), 657 MB3.14 s, 2.63 s528 ms, 501 ms5.2×1.45 GiB32 MiB + 280 MiB
Scryfall cards (real data), JSON Lines, 656 MB3.10 s, 2.60 s525 ms, 496 ms5.2×1.45 GiB32 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.