Repository navigation
Releases
0.3.0 - 2026-11-15
Release Notes
TypeScript input works right after installing, because the releases bundle
the TypeScript 7 compiler; the playground reads large files on several
workers, 17 to 25 times as fast as quicktype in the browser; five bugs in
the code quicktype generates are fixed, with every other output unchanged;
JSON Lines in the npm package and the playground; and every hash map is
seeded, which changes the Rust API's map types.
Added
-
JSON Lines in quickertype-core (npm): a source given
jsonLines: true(addSource({ name, samples, jsonLines: true }), and
addSourceSync) reads each of its samples, a string or its UTF-8 bytes
(aUint8Arrayor a Node.jsBuffer), as JSON Lines: one JSON value
per line, typed as the JSON array of those values, so the output is
what quicktype gives for that array, in every language and with every
option, as with the CLI's JSON Lines. WithoutjsonLinesa sample is
one JSON value, as in quicktype. The rules are the CLI's:\nor
\r\nline breaks, blank lines skipped, a value may span lines, a byte
order mark may come first, two values on one line are an error, and a
sample without values is[]. Each value is read asJSON.parsereads
a JSON sample; a syntax error names the line its value starts on, then
givesJSON.parse's message for that value (Syntax error in input JSON Cards: line 3: Expected ',' or '}' after property value in JSON at position 9; for a second value on a line,line N: Unexpected non-whitespace character after JSON), the same on both engines, and a
sample that fails adds nothing to the input. The WebAssembly engine
reads JSON Lines as fast as the same values as an array (a 40 MB file
as bytes in 115 ms, the array in 116 ms, in Node), and bytes as they
are; elsewhere (the TypeScript engine, bytes that are not UTF-8) each
value is decoded, parsed and handed to the input by itself, so neither
the whole text nor all the values are held at once, and bytes too large
for one string work there too. JSON Lines need a
CompressedJSONFromStringwhoseparseandparseSyncare its own;
with anotherCompressedJSON,addSourcethrows a plainErrorthat
says so. In the.d.tsfiles,JSONSourceDatahas the optional
jsonLinesfield. -
JSON Lines in the playground: a
.jsonlor.ndjsonfile (by its
extension, in any case), opened, chosen or dropped, is read as JSON
Lines, and so is text typed or pasted with the new input kind JSON
Lines (the CLI's--src-lang jsonl). The command under the output is
the CLI's (quickertype --lang typescript --top-level Cards cards.jsonl), with--src-langonly where the input's kind is not
what its name says. quicktype, which has no JSON Lines, is given the
JSON array of the values for the comparison, made in its worker from
quickertype-core's own scan of them (for a file, in the buffer its
bytes are read into), and the two outputs are identical; for text that
is not JSON Lines, the array is not JSON either. JSON Lines files open
at the same sizes as JSON files. Where the input pane is too narrow for
its controls on one row, the input kind fills the first, and the
output's head is as tall, so the rows under them still line up. -
quickertype-core and quickertype-js-compat: the
siphashfeature. It
hashes every map and set, and the JSON reader's tables, withstd's
SipHash-1-3 natively, keyed from the operating system's random source,
instead of foldhash: a keyed pseudorandom function, for an embedder that
hashes untrusted input on a server. It is slower and changes no output;
it has no effect on wasm32. -
TypeScript input works out of the box: the release archives, and
with them the Homebrew formula, thequickertypenpm package and the
MSI, include the TypeScript 7.0.2 compiler that TypeScript input needs:
Microsoft's, unmodified (the npm package
@typescript/typescript-<os>-<arch>for the platform, with its license
and notices), in atypescriptdirectory next toquickertype
(Homebrew:share/quickertype/typescript). quickertype looks for it
afterQUICKTYPE_TSCand beforenode_modulesandPATH, from its
executable's real path, so links to the binary work, and uses it only
when it is executable with the release'spackage.jsonandpins.json
beside it, without starting it to ask its version. A compiler the
system refuses to start gives an error with its path and the fix.cargo installand the shell and
PowerShell installers still give the binary alone; without a compiler,
the error now names the platform's package (npm install -g typescript@7.0.2, which installs
@typescript/typescript-darwin-arm64@7.0.2on Apple Silicon Macs) and
no longer ends in two periods. The release downloads each package from
the npm registry, checks it against the sha512 and compiler hash pinned
in
release/typescript/pins.json,
runs it on its build runner, and publishes nothing unless every archive
and the MSI have it. An archive grows by about 7 MB (the Windows zip by
about 9.5 MB). -
The MSI installs quickertype's
LICENSEandNOTICEin
C:\Program Files\quickertype. -
The playground reads large files on several workers: a JSON array
or JSON Lines file of 16 MiB or more is read in parts by up to eight
Web Workers at once, each with an engine instance of its own, by the
rules of the CLI's reader on several threads, and the parts' tallies
are appended in order in quickertype's worker. The output is what
reading the file in one go gives, byte for byte; where the parts do not
read (the file is broken, the engine declines a value, bytes that are
not UTF-8) or the CLI would read in one go, the file is read in one go,
with its errors. In headless Chrome on 8 workers, warm, reading and
running: the 100k records (27 MB) in 18 ms instead of 43, 100 MB of
cards in 107 ms instead of 397, and Scryfall cards (real data, 656 MB)
in 0.50 s instead of 2.6 s, the engine's WebAssembly memory 32 MiB
instead of 1.5 GiB, with 280 MiB in the part workers; against
quicktype in the same page, 17× to 25× faster warm on the first 100 to
537 MB of those cards
(BENCHMARKS.md). quickertype
now opens files of up to 2 GiB in the playground: those it reads in
parts at any size; in one go, JSON up to the longest string a browser
holds (512 MiB) and JSON Lines up to 1.25 GiB (what its engine holds,
measured), and past those it says the file is too large to read in one
go, and why it could not be read in parts; quicktype still says the file
is too large for the browser, now only when the file's text, counted in
UTF-16 units, does not fit one string (its bytes may be more: a 537 MB
slice of the cards fits), and never with an empty text, which Chrome
decodes such a text to without an error. Why a file was read in one go is
remembered for it where that is the file's own whatever the workers (no
split, not JSON there, trees far larger than their text); any other
reason (part workers that fail, which are replaced; a part too long for
this many workers' memory) is tried again once before it is remembered
too. The status under a file read so says "reading it on N workers". -
Reading in parts in quickertype-core (internal, not public API):
src/native/parallel.tsreads one sample of a fresh JSON input in parts
on several engine instances (bindings incrates/quicktype-wasm's
parts.rs, the rules in quickertype-core'sinput/parts.rs); the input
then holds the sample asaddSourcewould add it, its runs use the
tallies, and should anything read theCompressedJSON's tables, they are
filled by reading the sample again with TypeScript, or, if that fails,
the input is left as it was and the error says the tables cannot be had.
In Rust,
JsonInput::from_talliesand the portable trees' bytes
(PortableTree::to_bytes/from_bytes); the CLI's parallel reader
shares its plan and split helpers.
Changed
- Breaking for the Rust API: every
IndexMap,IndexSet,HashMap
andHashSetin the crates uses one seeded hasher,SeededState
(quickertype-js-compat's newhashmodule, which quickertype-core
re-exports assupport::fast_hash, with aliases of those four and
index_map_with_capacity). The maps in the public API
(JsonValue::Object,MultiFileRenderResult, the type graph's maps)
have it as their third type parameter, so code that made them with
IndexMap::new()makes them withIndexMap::default()(orcollect(),
orindex_map_with_capacity(n)).support::fast_hash::BuildHasheris
SeededStateon every target. quickertype-js-compat has the
js-host-randomfeature now, which quickertype-core's turns on. - Breaking for wasm32 embedders without
js-host-random:
support::fast_hash::seed(quicktype_js_compat::hash::seed) must come
before any other use of quickertype-core or quickertype-js-compat, since
every map takes its seed when it is made and parsing JSON or building
Optionsmakes maps; called later, it panics, saying so. Before, only
some maps took the seed, so parsing JSON first worked. The npm package
seeds withjs-host-random, as before. - The JavaScript API's engine no longer exports its test hooks
(__panicForTests,__pow,__pendingRuns,__jsonCount,
__jsonLeases,__jsonReadTrapForTests,__memoryGrowths,
__memoryPages) or, outside--heap-statsbuilds,__heapBytesand
__heapPeak; the facade never used them. The package's tests build an
engine of their own with them (quicktype-wasm'stest-hooksfeature). - The JavaScript API's engine, on a host without
crypto.getRandomValues,
fails to load with "quicke...
0.2.0 - 2026-11-14
Release Notes
Large JSON and JSON Lines files read on every core, JSON Lines input,
TypeScript input about three times as fast as quicktype's, a faster
WebAssembly engine for the JavaScript API, and the command renamed to
quickertype so that it installs beside quicktype.
Added
- JSON Lines input (not in quicktype): one JSON value per line, read
as the JSON array of those values, so a file of valuesV1…Vngives
exactly the code quicktype gives for[V1,…,Vn], in every language and
with every option.- The CLI reads files and URLs named
*.jsonlor*.ndjsonso (a
URL by its path, without the query), and so does a directory: its
*.jsonland*.ndjsonfiles as JSON Lines, its.jsonfiles as
JSON, and a.urlfile by its URL's name.--src-lang jsonlreads
every JSON input named on the command line so, standard input
included, and directories by the names as without it.--help
listsjsonlamong the source languages. - With an explicit
--src-langother thanjsonl(json,schema,
...), quickertype behaves exactly as quicktype: no input is JSON
Lines, and directories ignore.jsonland.ndjsonfiles. - This changes what
.jsonland.ndjsonfiles give without
--src-lang: quicktype reads such a file as one JSON value, so a
file with one line gave that value's type (say, an object) and now
gives an array of it; a file with more lines was a syntax error and
now works; and a directory, which ignored them, now reads them. Pass
--src-lang jsonfor quicktype's behavior. - Values are separated by line breaks (
\nor\r\n); blank lines
are skipped, the last line break is optional, a value may span lines
(a pretty-printed one), a byte order mark may come first, and two
values on one line are an error. A file without values is[]. A
syntax error names the line its value starts on (Syntax error in input JSON cards: line 3: …). - quickertype-core:
JsonSample::StringLines,StreamLinesand
ReaderLines, the JSON Lines forms ofString,Streamand
Reader. - Reading JSON Lines is as fast as reading the same values as an array,
a large file on several threads too (below).
- The CLI reads files and URLs named
- quickertype-core (npm): the JSON inputs of
jsonInputForTargetLanguage
take a sample as its UTF-8 bytes too (aUint8Arrayor a Node.js
Buffer, e.g.fs.readFileSync(path)), read as the text
new TextDecoder().decode(bytes)gives: without a leading byte order
mark, with U+FFFD for what is not UTF-8. The WebAssembly engine reads
the bytes as they are, without decoding them into a JavaScript string
and encoding that again into its memory: in Chrome, a run on a 27 MB
array of records takes 48 instead of 57 ms, and a 656 MB file, too large
to be a JavaScript string, can be read. - The CLI reads a large JSON file on several threads: a regular file
of 8 MiB or more whose top-level value is an array (or standard input
redirected from one, on Unix) is cut between its elements and read on
every core, into the same tallies as reading it in one go, so the
output is the same byte for byte. An array of 1 million records
(267 MB) becomes TypeScript types about 4.6 times as fast on 12 cores
(57 ms instead of 262 ms on an M2 Max).
The memory the parts read beside each other take is bounded; pipes and
smaller files are read in one go as before.- JSON Lines too: a JSON Lines file of 8 MiB or more (or standard
input redirected from one with--src-lang jsonl) is cut between its
lines and read so, with the output and the errors of reading it in
one go, a bad line reported on the same line. 1 million records as
JSON Lines (266 MB) take 54 instead of 283 ms on 12 cores, as long as
their array takes. - quickertype-core:
ParallelOptions(made from itsDefault) and
Readable::open_sample(options), which opens a file so that a large
top-level array in it (as aJsonSample::Reader), or large JSON Lines
(as aJsonSample::ReaderLines), is read on several threads.
- JSON Lines too: a JSON Lines file of 8 MiB or more (or standard
Changed
-
Breaking: the command is now
quickertype, notquicktype, so that
it installs beside the TypeScript quicktype (homebrew-core'squicktype
formula, npm'squicktypepackage). Its arguments, output files and
messages are quicktype's as before;--helpnames the command
quickertypein its synopsis and examples. To keep typingquicktype,
addalias quicktype=quickertypeto your shell's startup file; scripts,
Makefiles and CI don't read aliases, so for them put a symlink named
quicktypetoquickertypein a directory on theirPATH
(ln -s "$(command -v quickertype)" ~/.local/bin/quicktype). The
packages, archives and installers keep their names.0.1.0 installed the command as
quicktype. Upgrading with Homebrew
(brew upgrade quickertype), npm (npm install -g quickertype) or the
MSI removes it. The others leave it where 0.1.0 put it:- the shell installer: delete
$CARGO_HOME/bin/quicktype
(~/.cargo/bin/quicktypeby default); - the PowerShell installer: delete
%CARGO_HOME%\bin\quicktype.exe
(%USERPROFILE%\.cargo\bin\quicktype.exeby default); cargo install: it installs the new version beside 0.1.0's
$CARGO_HOME/bin/quicktypeand lists both (cargo install --list);
cargo uninstall quickertype@0.1.0deletesquicktypeand keeps
quickertype;- an archive from the GitHub Release: delete its
quicktypewherever
you put it.
If you unlinked homebrew-core's
quicktypefor 0.1.0,
brew link quicktypelinks it again. - the shell installer: delete
-
Breaking for the Rust API:
DateTimeRecognizerisSend + Sync
(the threads that read a large file share the recognizer). The
built-in recognizers are; a recognizer that holds anRcor a
RefCellno longer compiles. -
JSON with many URIs infers faster, in the CLI and in the JavaScript
API's WebAssembly engine: a plain URI's protocol and extension are read
without parsing it whole, and its attributes are made only where they
add something. On a 100 MB dump of trading cards, with 27 URIs per
card, the CLI takes 0.20 instead of 0.40 s of CPU, and the engine in
Chrome 0.48 instead of 0.81 s foraddSourceand a run. The engine
also holds less while it reads a large sample: its peak on those cards
goes from 286 to 225 MiB. -
The JavaScript API's WebAssembly engine keeps the tallies a run inferred
an input's types from with the input's samples, so that the next run on
the same input (another language, other options) does not walk them
again: generating the 20 MB benchmark input a second time takes 13.9
instead of 46.9 ms in Chrome. They count toward the engine's limit on
the memory its inputs hold, and are dropped when a sample is added. -
quickertype-core:
JsonInput::inferred_from(andJsonInference) tells
where an input inferred its types from;JsonInput::set_keep_tallies
keeps the tallies of a compressed form with it. An error while tallying
a compressed form is reported instead of falling back to its values. -
The WebAssembly engine reads large JSON samples 7–11% faster (the 20 MB
benchmark input: 96 instead of 103 ms in Chrome). The reader's string
and key tables hash each string with foldhash'swritealone, without
the end marker thatHash for stradds, which costs a call and four
multiplies in WebAssembly. -
TypeScript input is 2.2 to 3.4 times as fast as quicktype's (it
was slower from about 2,000 interfaces on): 10,000 interfaces that
refer to each other become Rust in 5.5 instead of 23 s (quicktype:
17 s), and 10,000 interfaces shaped like an API's typings in 8.4
instead of 25 s (quicktype: 28 s). The questions to the TypeScript 7
compiler go out in a few pipelined batches instead of one round trip
each (909,000 for those 10,000 interfaces; now 29 requests one at a
time and 8 batches), answers are cached, and JSDoc that cannot exist is
not asked for. Output is unchanged. See
docs/BENCHMARKS.md.QUICKTYPE_TSC_STATS=1prints the requests to the compiler, by
method, when a conversion ends.
-
Inputs with thousands of types render faster in every language and
input kind: four steps of the engine were quadratic in the number of
types (expanding JSON Schema enums, checking name conflicts, taking
named namespaces off the naming queue, and collecting declarations).
For the schema of 10,000 TypeScript interfaces, expanding strings takes
0.10 instead of 2.4 s, and rendering Rust 0.28 instead of 4.1 s.
Fixed
- Partly fixed: the JavaScript API's WebAssembly engine seeded its hash
maps the same in every instance, because WebAssembly has no randomness of
its own, and whoever knows the seed can craft keys that collide. Now the
JSON reader's string and key tables and the engine's otherfast_hash
maps take their seed fromcrypto.getRandomValues, per instance. An
engine on a host withoutcrypto.getRandomValuesfails to load, with an
error naming it. Not fixed yet: theIndexMaps andIndexSets on
std'sRandomState(class properties, enum and string cases,
JsonValueobjects) still have fixed keys in WebAssembly, so crafted
property names can still slow inference there; a later release seeds
them too (see
Hash seeds in WebAssembly).
Install quickertype 0.2.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/EloB/quickertype/releases/download/v0.2.0/quickertype-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/EloB/quickertype/releases/download/v0.2.0/quickertype-installer.ps1 | iex"...
0.1.0 - 2026-11-13
Release Notes
The first release: the quicktype CLI, ported to Rust, as prebuilt binaries
and installers.
Added
- The
quicktypecommand-line tool. It is a port of the TypeScript
quicktype 24.0.0 (commit
c39af7d3) with the same flags, help text, output files, messages and
exit codes, byte for byte. All 11,177 recorded runs of the TypeScript CLI
intests/goldenmatch, andcargo xtask paritychecks every change
against them. - Every input: JSON (including samples streamed from large files),
JSON Schema, GraphQL (schema and queries, plus--graphql-introspect),
Postman collections, URLs, and TypeScript. TypeScript input needs the
TypeScript 7.0.2 native compiler, installed with
npm install -g typescript@7.0.2or named byQUICKTYPE_TSC. - All 27 output languages and their renderer options.
- Speed: 8 to 96 times faster than the TypeScript CLI per run, and
46 times faster over the whole golden corpus, see
docs/BENCHMARKS.md.
The binary uses the mimalloc allocator. - Releases for macOS (Apple Silicon and Intel), Linux (x86_64 and
aarch64 with glibc, x86_64 with musl) and Windows (x86_64), as archives
with SHA-256 checksums, shell and PowerShell installers, a Homebrew
formula (brew install EloB/tap/quickertype), an npm package
(npm install -g quickertype), an MSI, and thequickertypecrate
(cargo install quickertype, with Rust 1.88 or newer). Each of these
installs a binary namedquicktype, which conflicts with the TypeScript
quicktype's, see
docs/RELEASING.md. - The JavaScript API on npm as
quickertype-core:
quicktype'squicktype-coreAPI with the engine compiled to WebAssembly,
a drop-in replacement (change the import), for Node.js 20+ and browsers. - The Rust API on crates.io as
quickertype-core(imported
asquicktype_core), withquickertype-js-compat,
quickertype-graphql-inputandquickertype-typescript-input. - Windows builds and tests in CI. File names on Windows follow Node's
path.win32, as the TypeScript CLI's do there.
Known issues
- Divergences from quicktype that no recorded case exercises are listed in
docs/PARITY.md.
Install quickertype 0.1.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/EloB/quickertype/releases/download/v0.1.0/quickertype-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/EloB/quickertype/releases/download/v0.1.0/quickertype-installer.ps1 | iex"Install prebuilt binaries via Homebrew
brew install EloB/tap/quickertypeInstall prebuilt binaries into your npm project
npm install quickertype@0.1.0Download quickertype 0.1.0
| File | Platform | Checksum |
|---|---|---|
| quickertype-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| quickertype-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| quickertype-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| quickertype-x86_64-pc-windows-msvc.msi | x64 Windows | checksum |
| quickertype-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| quickertype-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
| quickertype-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |