jaq: a jq clone in Rust with YAML, CBOR, TOML and XML support
A jq clone focussed on correctness, speed, and simplicity
At a glance
- What is it?
- jaq is a drop-in replacement for jq written in Rust, built around correctness, speed and a small implementation. It also ships as jaq-core, a library for running jq programs inside Rust.
- Who is it for?
- Adopt jaq if you already write jq filters, want the extra input formats, or need to embed a jq engine in a multi-threaded Rust program through jaq-core. Do not adopt it if you depend on jq features the manual does not cover, or if you need a binary you can audit against a specific release: the README points at the releases page for Linux, Mac and Windows builds, but it does not document how those binaries are produced.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What jaq replaces, and the case it was built for
jq 1.6 was slow to start, roughly 50ms according to the jaq README, and that cost shows up when a script shells out to jq once per file. jaq was written to remove that overhead, and the benchmark table in the README puts the `empty` benchmark at 410ms for jaq-3.0 against 430ms for jq-1.8.1, with gojq-0.12.18 at 270ms. Startup is not where jaq wins by the widest margin, but it is the reason the project exists. The audience is anyone who already has jq filters in a pipeline and wants them to run faster, plus Rust developers who want to evaluate jq expressions without shelling out at all. The README describes jaq as two things: the `jaq` command-line program, usable as a drop-in replacement for jq, and `jaq-core`, a library for compiling and running jq programs inside Rust programs. The library angle is the part jq does not offer in the same shape. According to the README, `jaq-core` can be safely used in multi-threaded environments and supports arbitrary data types beyond JSON.
The workspace split: jaq-core, jaq-std, jaq-json, jaq-fmts, jaq-all
jaq is not a single crate. The workspace in Cargo.toml lists seven members: `jaq-core`, `jaq-std`, `jaq-json`, `jaq-fmts`, `jaq-all`, `jaq`, and `jaq-play`. That split is the actual architecture. `jaq-core` holds the evaluator and the `ValT` trait, which is what makes non-JSON value types possible. `jaq-std` supplies the standard library of filters. `jaq-json` binds JSON values to the core. `jaq-fmts` is where the extra formats live, which is why YAML, CBOR, TOML and XML are a feature of the CLI rather than something baked into the evaluator. `jaq-all` assembles a complete engine from those pieces, and `jaq` is the binary on top. The workspace pins each crate at its own version: jaq-core 3.1.1, jaq-std 3.0.3, jaq-json 2.0.3, jaq-fmts 0.1.1, jaq-all 0.3.0. The release profile sets `strip = true` and `codegen-units = 1`, both of which trade compile time for a smaller, faster binary. If you embed jaq, you pick the crates you need rather than pulling the whole CLI. The cost is that you have to track five version numbers instead of one.
Installing jaq and running a first filter
The README gives several install paths. On macOS or Linux, Homebrew is the shortest. The README also notes that `brew install --HEAD jaq` builds the latest development version, which you should not do on a machine you depend on. The command below installs the released formula.
brew install jaqIf you prefer not to use Homebrew, the README documents a direct download for Linux. It fetches the musl binary matching your architecture, marks it executable, and leaves it in the current directory, so you decide where it ends up.
curl -fsSL https://github.com/01mf02/jaq/releases/latest/download/jaq-$(uname -m)-unknown-linux-musl -o jaq && chmod +x jaqWith a Rust toolchain installed, cargo is the third route. The README states that both cargo commands place the executable at `~/.cargo/bin/jaq` on its author's system. The `--locked` flag makes cargo use the committed Cargo.lock rather than resolving fresh versions.
cargo install --locked jaqOnce installed, a first filter looks exactly like jq. The repository ships example filters under `examples/`, including `examples/ball.jq`, `examples/bottles.jq`, `examples/table.jq` and `examples/tar.jq`, with shell wrappers `examples/ball.sh` and `examples/tar.sh`. The README's own benchmark table shows the shape of a jq one-liner that jaq also runs: it reads a JSON array of benchmark results and formats each entry into a table row.
jq -rs '.[] | "|`\(.name)`|\(.n)|" + ([.time[] | min | (.*1000|round)? // "N/A"] | min as $total_min | map(if . == $total_min then "**\(.)**" else "\(.)" end) | join("|"))' bench.jsonThat command is copied from the README, where the author notes you can use jaq in its place. Because the README calls jaq a drop-in replacement for jq, the usual next step is to point an existing script at `jaq` instead of `jq` and compare output. The README does not document a rollback procedure, so keep the jq binary in place until you have compared results on your own data.
Where jaq is faster, and where it is not
The README's benchmark table is generated by `bench.sh` and compares jaq-3.0, jq-1.8.1 and gojq-0.12.18 on an AMD Ryzen 5 5500U. Read the table as the author's own measurement, not as a general guarantee. jaq wins most rows by a wide margin: `upto` at 0ms against 440ms and 450ms, `group-by` at 260ms against 1790ms and 1580ms, `tree-contains` at 90ms against 830ms and 230ms. It also loses some. `ex-implode` goes to gojq at 560ms against jaq's 600ms. `reduce` and `try-catch` both go to jq, 700ms against 740ms and 200ms against 220ms. `pyramid` goes to jq at 250ms against 300ms. `ack` goes to jq at 490ms against 570ms. `tree-flatten` is the worst case for jaq: gojq finishes in 10ms, jq in 330ms, jaq in 700ms. The `defs` row is worth noting for a different reason. jq shows N/A, meaning error or more than 10 seconds, while jaq finishes in 50ms and gojq in 960ms. So there are workloads where jq does not complete and jaq does. The honest summary is that jaq is usually faster and occasionally slower, and the slow rows are concentrated in recursive tree operations.
The compatibility boundary and the failure mode to expect
The README says jaq aims to provide a more correct and predictable implementation of jq while preserving compatibility with jq in most cases. That phrase, in most cases, is the limitation. jaq is a clone, not a reimplementation of the same source, so any filter that depends on a jq behaviour the jaq manual does not describe is a candidate for a silent difference. The failure mode is not a crash. It is a filter that returns a different value, or a different number of values, on a pipeline where nobody is checking. The `defs` benchmark row is a reminder that the two implementations do not agree on what is even computable in a given time. If your filters use recursion heavily, the benchmark table suggests jaq may be the slower choice, and `tree-flatten` is the clearest example. jaq is also the wrong tool if you need jq's own module ecosystem or a specific jq release's exact semantics, because jaq versions its crates independently of jq. Finally, the README does not describe how the released binaries are built or signed, so an environment with binary provenance requirements has to start from source with `cargo install --locked jaq`.
gojq as the alternative, and how the approaches differ
gojq appears throughout the README's benchmark table and is the obvious comparison point. Both are jq clones, but they are written in different languages and the README's numbers show they do not occupy the same position. gojq wins the `empty` startup benchmark at 270ms against jaq's 410ms and jq's 430ms, so if your workload is thousands of tiny invocations, gojq is the faster clone on that row. gojq also wins `ex-implode`, `range-prop` and `tree-flatten`, the last by a factor of seventy against jaq. jaq wins `defs`, `upto`, `reduce-update`, `reverse`, `sort`, `group-by`, `min-max`, `add`, `kv`, `kv-update`, `kv-entries`, `repeat`, `from`, `last`, `tree-contains`, `tree-update`, `tree-paths` and `to-fromjson`. The other difference is the library story. The README presents `jaq-core` as usable in multi-threaded Rust and able to carry arbitrary data types through the `ValT` trait. Neither property is claimed for gojq in this material. If you are choosing between them, the benchmark table is the evidence you have, and it favors jaq for bulk array and object operations and gojq for startup and recursive tree work.
Licence, release cadence and the cost of upgrading
jaq is MIT licensed, with the file named LICENSE-MIT in the repository root. MIT is permissive, so embedding `jaq-core` in a closed product is the kind of use the licence is designed to allow, but read the licence text yourself rather than treating this as legal advice. The upgrade cost comes from the workspace layout. Recent releases are v3.1.1 on 2026-08-05, v3.1.0 on 2026-06-11 and v3.0.0 on 2026-03-27, and the last push to the repository was on 2026-08-28. The crate versions in the workspace do not move together: the CLI is at 3.1.1 while jaq-std is at 3.0.3, jaq-json at 2.0.3, jaq-fmts at 0.1.1 and jaq-all at 0.3.0. If you depend on `jaq-core` directly, a bump in the CLI does not tell you whether the core changed. Track the crate you actually depend on, and check the manual at the URL the README gives, since the README does not publish a changelog for API breaks. The `--locked` flag on the cargo install commands is the cheap insurance here: it keeps a build reproducible against the committed Cargo.lock instead of resolving newer versions at install time.
Editorial conclusion
Adopt jaq if you already write jq filters, want the extra input formats, or need to embed a jq engine in a multi-threaded Rust program through jaq-core. Do not adopt it if you depend on jq features the manual does not cover, or if you need a binary you can audit against a specific release: the README points at the releases page for Linux, Mac and Windows builds, but it does not document how those binaries are produced. Before committing, run your largest existing filter against both jq and jaq and compare the output, then check the manual for the builtins your filter uses. The README states that jaq preserves compatibility with jq in most cases, not all of them.
Frequently asked questions
Do I have jq installed?
jaq does not require jq to be present. The README presents jaq as a clone of jq and a drop-in replacement for it, and the installation section covers downloading a binary, Homebrew and cargo without mentioning jq as a dependency.
How do I install jaq with cargo?
Run `cargo install --locked jaq` with a Rust toolchain available. The README states that this places the executable at `~/.cargo/bin/jaq`, and that a `--git` variant installs the latest development version instead.
What does jaq-core let me do that jq does not?
The README states that jaq-core can be safely used in multi-threaded environments and supports arbitrary data types beyond JSON through the `ValT` trait. jq's own API is not described that way in this material.
Which data formats does jaq support besides JSON?
The README lists YAML, CBOR, TOML and XML as features not present in jq. The workspace places that support in the `jaq-fmts` crate.
Is jaq faster than jq?
On most rows of the README's benchmark table jaq-3.0 finishes ahead of jq-1.8.1, but jq wins `reduce`, `try-catch`, `pyramid` and `ack`, and gojq-0.12.18 wins `tree-flatten` by a wide margin. The table was generated with `bench.sh` on the author's own machine.
What is the licence for jaq?
jaq is MIT licensed, with the licence file named LICENSE-MIT in the repository root.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/01mf02-jaq)