CLI tool
wader/fq avatar
wader/fq

fq: querying binary formats with jq, one decoder layer at a time

fq - jq for binary formats. Tool, language and decoders for working with binary formats.

10,635 stars257 forksGoNOASSERTION

At a glance

What is it?
fq is a Go tool, language and decoder set that puts jq expressions inside binary files, with 136 named decoders for media, containers, network captures and serialization formats. Its rough edges are a format name per structure rather than per file, a Go version floor that its own go.mod contradicts, and packaging that ranges from a Homebrew tap to an Alpine edge testing tree.
Who is it for?
Reach for fq when you already write jq and your files are containers, media, wire captures or serialized blobs, since the expression language is the whole point. Choose binspector, a hex editor or kaitai when your workflow is not query shaped.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • wader/fq10,635 ★ · +39
Star history
Repository2026-09-222026-11-14
wader/fq10.6k10.6k

39 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Three ways to invoke fq, all of them jq

fq has three shapes of invocation:

sh
fq . file
fq d file
fq 'some query' file ...

The expression language is not fq's own. go.mod requires github.com/wader/gojq v0.12.1-0.20260709150221-6128faeeac7b, a fork of itchyny/gojq, and the credits section names stedolan's jq as the language being borrowed. The docs tell you to learn more about jq to get the most out of fq, and the interactive REPL with auto-completion is where you find out which jq habits carry over. For a reader that means jq fluency, not fq fluency, is the real prerequisite, and a jq tutorial is the actual onboarding material. A `.` dump is the debugging starting point, `d` is the shorthand for decode, and the third form is where you do the work.

The catalog names structures, not file extensions

The 136 decoder names are per structure, not per extension, and this is where people get stuck. The AVC family contributes avc_annexb, avc_au, avc_dcr, avc_nalu, avc_pps, avc_sei and avc_sps, sitting beside hevc_annexb, hevc_au, hevc_dcr, hevc_nalu, hevc_pps, hevc_sps and hevc_vps. FLAC splits into flac_frame, flac_metadatablock, flac_metadatablocks, flac_picture and flac_streaminfo. Bitcoin arrives as bitcoin_blkdat, bitcoin_block, bitcoin_script and bitcoin_transaction. You pick a layer explicitly with -d, as in:

sh
go run . -d mp3 . file.mp3

and nested formats select their own sub-decoders when you do not. The consequence for a reader is that identifying the container is only half the job. You still have to know which layer you want, or you will read a file at the wrong altitude and conclude the parser is broken when your -d choice was.

The decoder list is the ceiling, and no entry is a catch-all

fq ships a fixed catalog and that catalog is the ceiling. The format list in the README is itself produced by running the tool, `fq -rn -L doc 'include "formats"; formats_list'`, and the decoder dependency diagram in the repository is generated by piping `./fq -rnf doc/formats_diagram.jq` into graphviz dot. Nothing in that list parses an arbitrary container. What sits at the bottom is `bytes` and `bits`, alongside text shapes such as json, csv, xml, yaml, toml and markdown, and the note about other serialization formats is hedged as working for some of them. The consequence is blunt: a file whose format has no decoder is not interpreted, it is shown as raw bytes, and every field after that is something you decode by hand inside an expression. doc/dev.md is where you go to write the missing decoder yourself.

The Go floor in go.mod is higher than the one in the docs

The build instructions state a version floor that the module file contradicts. The install section says to make sure you have go 1.22 or later installed. go.mod declares `go 1.26.0`, and the Dockerfile starts from `FROM golang:1.27.3-bookworm AS base`. A machine with Go 1.22 through 1.25 therefore passes the prose check and then runs into the module toolchain line, producing a Go error rather than an fq one. Treat go.mod as the real requirement. The two go install lines also hand you different binaries:

sh
# build and install latest release
go install github.com/wader/fq@latest

# build and install latest master
go install github.com/wader/fq@master

# copy binary to $PATH if needed
cp "$(go env GOPATH)/bin/fq" /usr/local/bin

@latest resolves to a tag, and the newest release listed is v0.18.0 from 2026-08-25, while @master gives untagged master pushed on 2026-10-31. So two colleagues who both say they built fq from source can be running different code, and only one of them can quote a version number.

Supported on Alpine means installed from the edge testing tree

Package coverage is uneven, and Alpine is the clearest case. The notes say fq is currently in edge testing but should work fine in stable, and the install line hands apk an explicit repository with -X:

code
apk add -X http://dl-cdn.alpinelinux.org/alpine/edge/testing fq

On a stable system that opts a single tool into the testing tree. Guix offers a development shell plus a profile install, Arch offers the extra repository package plus a separate AUR VCS package, and macOS has three routes: a Homebrew tap, MacPorts, and unarchiving a release yourself. FreeBSD and Gentoo have plain ports and one `emerge dev-util/fq`. The consequence for a reader is that the word supported carries a different weight on each system. On Alpine you are opting into an edge package by default, and on macOS one of the three routes means quarantined binaries and a manual Gatekeeper step.

macOS can refuse the binary before fq reads a byte

On macOS a release binary can be rejected before fq executes anything, and the refusal comes from the operating system rather than from the tool. The documented fix is a pair of commands aimed at the file:

sh
xattr -d com.apple.quarantine fq
# for macOS version before Sequoia you might need this also
spctl --add fq

The alternative route described is to run the binary once, ignore the warning, and allow it in security preferences. The consequence is that a first run can look like a corrupt download when the download is fine. The quarantine attribute is the entire problem, no fq output points at it, and the spctl line only applies before macOS Sequoia. Installing through a package manager sidesteps this entirely, which is the practical reason to prefer brew or port on a Mac.

Running the test suite needs expect and a deliberately empty HOME

Contributors hit constraints the user-facing install steps never state. One target builds and tests at once:

sh
# run all tests and build binary
make test fq

`test` expands to testgo, testjq and testcli, and testcli drives three expect scripts, pkg/cli/test_repl.exp, pkg/cli/test_cli_ctrlc.exp and pkg/cli/test_cli_ctrld.exp, through pkg/cli/test_exp.sh. The Dockerfile exists partly for that reason: it installs expect with apt-get in the base stage before the builder stage runs the same target, then copies the static binary into a scratch image. The jq tests are run with HOME pointed at a directory that does not exist, and the Makefile comment says this is to avoid accidentally including the config dir. Two consequences follow. A CI image without expect cannot run the CLI tests at all, and a regression that only appears once a user config file is loaded will slip past the jq suite, because config is excluded on purpose.

binspector and kaitai overlap, and Wireshark points at JSON

The competing tools named under similar works differ in ways that decide the choice. binspector is described as a binary format analysis tool with a query language and a REPL. kaitai is declarative binary format parsing, so it suits a committed spec file rather than an ad hoc question. Wireshark arrives with the tip `tshark -T json`. HexFiend and ImHex are hex editors, and HexFiend is a macOS editor with format template support. If your job is reading one structure once to answer a question, the jq expression language is the reason to use fq. If it is editing bytes by hand, a hex editor fits better. Repository metadata reports the license as NOASSERTION, so read LICENSE before shipping fq inside anything you distribute.

Editorial conclusion

Reach for fq when you already write jq and your files are containers, media, wire captures or serialized blobs, since the expression language is the whole point. Choose binspector, a hex editor or kaitai when your workflow is not query shaped. Before you build it, match go.mod rather than the install prose, and read LICENSE first, because the repository reports its license as NOASSERTION.

Frequently asked questions

What is a binary file format?

For fq's purposes a binary format is a byte layout that a named decoder turns into jq values, so the bytes become queryable, sliceable and concatenable with the same expressions you would use on JSON. The 136 decoders span media such as mp3 and mp4, containers such as matroska, zip and avro_ocf, system formats such as elf and macho, and text plus serialization shapes such as json, csv, xml and yaml.

Does fq require a separate jq binary to be installed?

No install method lists a separate jq binary. go.mod requires github.com/wader/gojq v0.12.1-0.20260709150221-6128faeeac7b, a fork of itchyny/gojq, so the expression engine is built into the fq executable rather than shelling out to jq.

Which Go version do I need to build fq from source?

The install text says go 1.22 or later, but go.mod declares `go 1.26.0` and the Dockerfile builds on golang:1.27.3-bookworm. Use go.mod as the floor, since that is the line the module toolchain enforces.

How do I choose which fq decoder to use on a file?

Names are per structure rather than per extension, so an AVC file can be read as avc_nalu, avc_au, avc_annexb, avc_sps, avc_pps, avc_sei or avc_dcr rather than through one h264 entry. Select one explicitly with -d, the way `go run . -d mp3 . file.mp3` does.

Can fq be installed with pacman, brew, scoop, port, guix and nix?

The documented routes are brew on macOS, `sudo port install fq` via MacPorts, `scoop install fq` on Windows, `pacman -S fq` and the AUR package `paru -S fq-git` on Arch, `emerge dev-util/fq` on Gentoo, `nix-shell -p fq` on Nix, two guix forms, a FreeBSD port, and an apk line pointing at the edge testing repository on Alpine.

Official sources

  1. Issues
  2. Project website
  3. README
  4. Releases
  5. wader/fq on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/wader-fq.svg)](https://hysenlabs.com/projects/wader-fq)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/wader-fq.svg)](https://hysenlabs.com/projects/wader-fq)

Was this useful?