jaq

A correct, fast jq clone written in Rust, with improved error messages and a more predictable handling of edge cases.

jaq (pronounced like "Jacques") is a reimplementation of jq in Rust. It aims to be a drop-in replacement for the most common jq use cases while fixing a number of correctness issues, producing clearer error messages, and running faster on large inputs.

If you already know jq, you already know most of jaq — the filter language is largely compatible. The differences are intentional improvements rather than oversights.

Features

  • jq-compatible — the vast majority of real-world jq filters work in jaq without modification
  • Correctness improvements — fixes several jq edge cases around limit, first, last, ?// (the try-alternative operator), and arithmetic on special values
  • Better error messages — type errors and parse failures are reported with more context and precision
  • Fast — typically faster than jq on large inputs thanks to Rust's performance characteristics
  • Streaming support — can process newline-delimited JSON (ndjson) efficiently
  • No external dependencies — a single self-contained binary

Installation

cargo install jaq

Or via your system package manager:

# macOS
brew install jaq

# Arch Linux
pacman -S jaq

# Debian / Ubuntu (Debian 13+)
apt install jaq

# Fedora
dnf install jaq

# Nix
nix-env -iA nixpkgs.jaq

Usage

jaq accepts the same command-line flags as jq, so existing scripts and aliases can be swapped in with no changes:

# Pretty-print a JSON file
jaq . file.json

# Extract a field
jaq '.name' file.json

# Extract a nested field
jaq '.user.email' file.json

# Filter an array
echo '[1,2,3,4,5]' | jaq '[.[] | select(. > 3)]'
# → [4, 5]

# Map over an array
echo '[1,2,3]' | jaq '[.[] * 2]'
# → [2, 4, 6]

# Get the keys of an object
echo '{"a":1,"b":2}' | jaq 'keys'
# → ["a", "b"]

# Compact output (no pretty-printing)
jaq -c '.items[]' file.json

# Raw string output (no JSON quoting)
jaq -r '.name' file.json

# Slurp all inputs into an array
jaq -s '.' *.json

# Read raw text input line by line
jaq -R 'split(",")' data.csv

Working with APIs

# Fetch and explore a JSON API response
curl -s https://api.github.com/repos/01mf02/jaq \
  | jaq '{name, stars: .stargazers_count, language}'

# Extract all page URLs from a sitemap-style response
curl -s https://api.example.com/pages \
  | jaq '[.pages[].url]'

# Process newline-delimited JSON (ndjson)
cat events.ndjson | jaq -c 'select(.type == "click") | .payload'

Differences from jq

jaq intentionally diverges from jq in a handful of areas where jq's behaviour is surprising or incorrect:

Behaviourjqjaq
limit(0; expr)May evaluate exprNever evaluates expr
nan == nanfalsefalse (consistent with IEEE 754)
null arithmeticVariesStrict type errors
?// (try-alternative)InconsistentWell-defined semantics
Error messagesOften crypticPrecise and contextual

For the overwhelming majority of everyday jq usage — filtering, transforming, and extracting from JSON — the two tools are interchangeable.