If you’ve ever tried to read a raw API response in your terminal, you know the pain. It’s usually a giant, unreadable wall of text that makes finding a single value feel like searching for a needle in a haystack. This is exactly why I started using jq. Learning how to use jq for JSON is essentially like giving your terminal a superpower for data manipulation.

In my experience, jq is the ‘sed’ for JSON data. It allows you to slice, filter, map, and transform structured data with incredible speed. Whether you are automating a gh cli workflow automation or just debugging a local config file, jq is an indispensable tool in any developer’s kit.

Prerequisites

Before we dive into the syntax, you’ll need a few things ready:

[
  {
    "id": 1,
    "name": "Project Alpha",
    "status": "active",
    "tags": ["automation", "cli"],
    "metrics": { "cpu": 12, "ram": 512 }
  },
  {
    "id": 2,
    "name": "Project Beta",
    "status": "archived",
    "tags": ["legacy", "cli"],
    "metrics": { "cpu": 45, "ram": 1024 }
  }
]

Step-by-Step: Mastering jq Basics

1. Pretty Printing (The Basics)

The simplest way to use jq is for “pretty printing.” If you have a minified JSON file, simply passing the identity filter (the dot .) will format it for human readability.

cat data.json | jq '.'

This is the most common entry point for anyone learning how to use jq for JSON. It takes the raw stream and adds indentation and colors.

2. Accessing Properties

To grab a specific field, you use the dot notation. If your JSON is an object, .fieldname works. If it’s an array, you’ll need to iterate or index it. To get the names of all projects in our sample file:

cat data.json | jq '.[].name'

Here, .[] iterates over the array, and .name extracts the value from each object. This pattern is fundamental to modern unix commands list and data piping.

3. Filtering Data

One of the most powerful features is the select() function. Let’s say I only want projects where the status is ‘active’.

cat data.json | jq '.[] | select(.status == "active")'

As shown in the terminal output in the image below, jq filters out everything that doesn’t meet the boolean condition inside select().

Terminal window showing the result of a jq select filter on a JSON array
Terminal window showing the result of a jq select filter on a JSON array

4. Transforming and Mapping

Sometimes you don’t want the whole object; you just want a new structure. I often use this when preparing data for another tool. To create a simple list of project names and their RAM usage:

cat data.json | jq '.[] | {project: .name, memory: .metrics.ram}'

This creates a new JSON object for every entry in the original array, mapping .name to project and .metrics.ram to memory.

5. Advanced Slicing and Piping

You can pipe the output of one jq filter into another within the same command. For example, to get the tags of only the archived projects:

cat data.json | jq '.[] | select(.status == "archived") | .tags'

Pro Tips for CLI Efficiency

Troubleshooting Common jq Issues

When I first started, I ran into these three roadblocks frequently:

Issue Cause Solution
cannot index array with string Trying to access a key on an array instead of an object. Add .[] before the key name.
Output contains quotes ("value") Default jq output is valid JSON. Use the -r (raw) flag.
Filter doesn’t seem to work Incorrect nesting or pathing. Build your filter incrementally (start with ., then .[], etc).

What’s Next?

Now that you know how to use jq for JSON, you can start integrating it into your CI/CD pipelines or local automation scripts. If you’re looking to optimize your entire terminal experience, I highly recommend checking out my guide on modern unix commands to see what else can replace your legacy tools.

Want more automation tips? Subscribe to the newsletter or check out my latest post on GitHub CLI automation.