Skip to content

Releases

0.3.0 - 2026-11-15

Choose a tag to compare

@github-actions github-actions released this 15 Nov 10:49

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
    (a Uint8Array or a Node.js Buffer), 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. Without jsonLines a sample is
    one JSON value, as in quicktype. The rules are the CLI's: \n or
    \r\n line 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 as JSON.parse reads
    a JSON sample; a syntax error names the line its value starts on, then
    gives JSON.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
    CompressedJSONFromString whose parse and parseSync are its own;
    with another CompressedJSON, addSource throws a plain Error that
    says so. In the .d.ts files, JSONSourceData has the optional
    jsonLines field.

  • JSON Lines in the playground: a .jsonl or .ndjson file (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-lang only 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 siphash feature. It
    hashes every map and set, and the JSON reader's tables, with std'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, the quickertype npm 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 a typescript directory next to quickertype
    (Homebrew: share/quickertype/typescript). quickertype looks for it
    after QUICKTYPE_TSC and before node_modules and PATH, from its
    executable's real path, so links to the binary work, and uses it only
    when it is executable with the release's package.json and pins.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 install and 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.2 on 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 LICENSE and NOTICE in
    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.ts reads one sample of a fresh JSON input in parts
    on several engine instances (bindings in crates/quicktype-wasm's
    parts.rs, the rules in quickertype-core's input/parts.rs); the input
    then holds the sample as addSource would add it, its runs use the
    tallies, and should anything read the CompressedJSON'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_tallies and 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
    and HashSet in the crates uses one seeded hasher, SeededState
    (quickertype-js-compat's new hash module, which quickertype-core
    re-exports as support::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 with IndexMap::default() (or collect(),
    or index_map_with_capacity(n)). support::fast_hash::BuildHasher is
    SeededState on every target. quickertype-js-compat has the
    js-host-random feature 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
    Options makes maps; called later, it panics, saying so. Before, only
    some maps took the seed, so parsing JSON first worked. The npm package
    seeds with js-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-stats builds, __heapBytes and
    __heapPeak; the facade never used them. The package's tests build an
    engine of their own with them (quicktype-wasm's test-hooks feature).
  • The JavaScript API's engine, on a host without crypto.getRandomValues,
    fails to load with "quicke...
Read more

0.2.0 - 2026-11-14

Choose a tag to compare

@github-actions github-actions released this 15 Nov 01:57

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 values V1…Vn gives
    exactly the code quicktype gives for [V1,…,Vn], in every language and
    with every option.
    • The CLI reads files and URLs named *.jsonl or *.ndjson so (a
      URL by its path, without the query), and so does a directory: its
      *.jsonl and *.ndjson files as JSON Lines, its .json files as
      JSON, and a .url file by its URL's name. --src-lang jsonl reads
      every JSON input named on the command line so, standard input
      included, and directories by the names as without it. --help
      lists jsonl among the source languages.
    • With an explicit --src-lang other than jsonl (json, schema,
      ...), quickertype behaves exactly as quicktype: no input is JSON
      Lines, and directories ignore .jsonl and .ndjson files.
    • This changes what .jsonl and .ndjson files 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 json for quicktype's behavior.
    • Values are separated by line breaks (\n or \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, StreamLines and
      ReaderLines, the JSON Lines forms of String, Stream and
      Reader.
    • Reading JSON Lines is as fast as reading the same values as an array,
      a large file on several threads too (below).
  • quickertype-core (npm): the JSON inputs of jsonInputForTargetLanguage
    take a sample as its UTF-8 bytes too (a Uint8Array or 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 its Default) and
      Readable::open_sample(options), which opens a file so that a large
      top-level array in it (as a JsonSample::Reader), or large JSON Lines
      (as a JsonSample::ReaderLines), is read on several threads.

Changed

  • Breaking: the command is now quickertype, not quicktype, so that
    it installs beside the TypeScript quicktype (homebrew-core's quicktype
    formula, npm's quicktype package). Its arguments, output files and
    messages are quicktype's as before; --help names the command
    quickertype in its synopsis and examples. To keep typing quicktype,
    add alias quicktype=quickertype to your shell's startup file; scripts,
    Makefiles and CI don't read aliases, so for them put a symlink named
    quicktype to quickertype in a directory on their PATH
    (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/quicktype by default);
    • the PowerShell installer: delete %CARGO_HOME%\bin\quicktype.exe
      (%USERPROFILE%\.cargo\bin\quicktype.exe by default);
    • cargo install: it installs the new version beside 0.1.0's
      $CARGO_HOME/bin/quicktype and lists both (cargo install --list);
      cargo uninstall quickertype@0.1.0 deletes quicktype and keeps
      quickertype;
    • an archive from the GitHub Release: delete its quicktype wherever
      you put it.

    If you unlinked homebrew-core's quicktype for 0.1.0,
    brew link quicktype links it again.

  • Breaking for the Rust API: DateTimeRecognizer is Send + Sync
    (the threads that read a large file share the recognizer). The
    built-in recognizers are; a recognizer that holds an Rc or a
    RefCell no 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 for addSource and 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 (and JsonInference) 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's write alone, without
    the end marker that Hash for str adds, 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=1 prints 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 other fast_hash
    maps take their seed from crypto.getRandomValues, per instance. An
    engine on a host without crypto.getRandomValues fails to load, with an
    error naming it. Not fixed yet: the IndexMaps and IndexSets on
    std's RandomState (class properties, enum and string cases,
    JsonValue objects) 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 | sh

Install prebuilt binaries via powershell script

powershell -ExecutionPolicy Bypass -c "irm https://github.com/EloB/quickertype/releases/download/v0.2.0/quickertype-installer.ps1 | iex"

...

Read more

0.1.0 - 2026-11-13

Choose a tag to compare

@github-actions github-actions released this 14 Nov 00:04

Release Notes

The first release: the quicktype CLI, ported to Rust, as prebuilt binaries
and installers.

Added

  • The quicktype command-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
    in tests/golden match, and cargo xtask parity checks 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.2 or named by QUICKTYPE_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 the quickertype crate
    (cargo install quickertype, with Rust 1.88 or newer). Each of these
    installs a binary named quicktype, which conflicts with the TypeScript
    quicktype's, see
    docs/RELEASING.md.
  • The JavaScript API on npm as
    quickertype-core:
    quicktype's quicktype-core API 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
    as quicktype_core), with quickertype-js-compat,
    quickertype-graphql-input and quickertype-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 | sh

Install 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/quickertype

Install prebuilt binaries into your npm project

npm install quickertype@0.1.0

Download 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