fx: Why This Terminal JSON Viewer Has 20K Stars While jq Exists
Hook
Despite jq being the undisputed king of command-line JSON processing for over a decade, fx has accumulated 20,000+ GitHub stars by doing something radically different: making JSON exploration actually enjoyable.
Context
The command line has always had an awkward relationship with JSON. When APIs started returning JSON everywhere in the early 2010s, developers were stuck piping curl output through python -m json.tool just to make it readable. Then jq arrived and gave us a powerful query language—but it came with a learning curve steeper than regular expressions. You'd constantly Google "jq select array element" or struggle to remember the difference between map and map_values.
Anton Medvedev created fx to solve a different problem: what if you didn't have to memorize a domain-specific language just to poke around some JSON? What if exploring API responses felt more like using browser DevTools than writing awk scripts? fx takes the stance that most JSON exploration is interactive and exploratory, not production pipeline work. You're debugging a failed API call, inspecting a config file, or trying to understand a complex data structure. For these scenarios, you need speed and intuition, not a Turing-complete query language.
Technical Insight
fx's architecture centers on a dual-mode design: an interactive TUI for exploration and a command-line mode for scripting. When you pipe JSON into fx without arguments, it launches a full-screen terminal interface built on the Bubble Tea framework (a Go library for building terminal UIs). This isn't just syntax highlighting—it's a navigable tree where you can collapse nodes, search for keys, and see real-time updates as you type transformations.
The killer feature is how fx handles transformations. Instead of learning jq's syntax, you write JavaScript-like expressions. Here's the difference in practice:
# Get all users older than 25 with jq
curl api.example.com/users | jq '[.users[] | select(.age > 25)]'
# Same thing with fx (interactive mode)
curl api.example.com/users | fx
# Then type: .users.filter(u => u.age > 25)
# Or non-interactive
curl api.example.com/users | fx '.users.filter(u => u.age > 25)'
Under the hood, fx embeds a JavaScript runtime (goja, a pure-Go ECMAScript implementation) that evaluates your expressions against the parsed JSON structure. This is a fascinating architectural choice: instead of building yet another query DSL, Medvedev leveraged an existing language that most developers already know. The trade-off is execution speed—goja is slower than jq's compiled C—but for interactive use cases, the difference is imperceptible.
The TUI mode demonstrates thoughtful UX engineering. As you navigate the JSON tree, fx tracks your cursor position and maintains context about your current location in the data structure. When you start typing a transformation, it shows a split view: original data on top, transformed result below. This real-time feedback loop is what makes fx feel like a REPL for JSON rather than a one-shot filter.
Here's a more complex example showing fx's JavaScript runtime capabilities:
echo '{"prices": [10, 20, 30, 40]}' | fx 'this.prices.reduce((sum, p) => sum + p, 0) / this.prices.length'
# Output: 25
You have access to all standard JavaScript array methods, object destructuring, and even anonymous functions. For developers who live in JavaScript/TypeScript codebases, this is muscle memory. No mental context switch required.
The streaming architecture deserves attention too. fx doesn't load entire JSON files into memory before parsing. It uses Go's encoding/json decoder with a custom scanner that can handle newline-delimited JSON streams. This means you can tail log files and pipe them through fx transformations without memory issues:
tail -f app.log | fx '.level == "error"'
One subtle but powerful feature: fx supports "themes" that aren't just color schemes—they change how data types render. The default theme uses different colors for strings, numbers, booleans, and null, but you can customize it to highlight specific patterns in your data. This is implemented through a theming engine that applies ANSI color codes based on token types identified during JSON parsing.
Gotcha
The JavaScript-like syntax is both fx's greatest strength and its most deceptive limitation. It's "JavaScript-like," not "JavaScript." You can't import libraries, use async/await, or access Node.js APIs. The goja runtime implements ECMAScript 5.1, which means no modern JavaScript features like optional chaining or nullish coalescing. When you hit these boundaries, it feels jarring—like typing on a keyboard with random keys missing.
More critically, fx's query capabilities are fundamentally less powerful than jq for complex transformations. jq has built-in functions for recursion (recurse, walk), sophisticated path manipulation, and complex conditionals that would require writing actual loops in fx's JavaScript. If you need to recursively transform all values matching a pattern deep in a nested structure, jq will do it in one line. In fx, you'll write imperative code that quickly becomes unwieldy. The tool also struggles with extremely large JSON files (gigabytes) where jq's streaming parser and lower memory overhead shine. And while the TUI is beautiful for exploration, it's completely unusable over SSH connections with high latency or in CI/CD environments where you only have non-interactive shells.
Verdict
Use fx if you're doing interactive JSON exploration during development—debugging API responses, inspecting configuration files, or understanding unfamiliar data structures. It's perfect for teams already deep in JavaScript who find jq's syntax alien, and it shines when you need to quickly filter/transform data without consulting documentation. The TUI mode is genuinely delightful for visual learners who prefer navigating data structures over writing queries blind. Skip fx if you're building production data pipelines where jq's performance and comprehensive function library matter, if you need advanced query features like recursive descent or complex path manipulation, or if you work primarily over SSH where TUI applications are painful. Also skip it if you're already fluent in jq—learning fx won't make you more productive, just comfortable in a different syntax. For quick local exploration with a side of JavaScript familiarity, fx is unbeatable. For everything else, jq remains king.