Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

jq: process JSON on the command line

By updated

Improve this page

jq is a command-line tool designed to read, filter and transform data in JSON (in French) format. In a world where APIs (in French) and configuration files rely massively on this format, jq becomes essential for any system administrator or DevOps developer.

Its main advantage: complex queries on nested data structures, straight from a terminal, without writing a Python script (in French) or JavaScript.

What you will learn

  • Read and format JSON from a file or a stream (stdin)
  • Extract precise fields with the filters .[], .key and indexes
  • Filter and transform with select, map and del
  • Combine conditions (and / or, contains) and sort (sort_by)
  • Fit jq into scripts and CI/CD pipelines

Install jq

jq is in the repositories of every distribution. For the latest version (jq 1.8.2), which fixes several security flaws, fetch the verified official binary.

Terminal window
# From the distribution repositories (often jq 1.7.x)
sudo apt install -y jq # Debian / Ubuntu
sudo dnf install -y jq # Fedora / RHEL / AlmaLinux
brew install jq # macOS
# Latest version as a binary (jq 1.8.2), verified through its SLSA attestation
JQ_VERSION=1.8.2
sudo curl -sSfL "https://github.com/jqlang/jq/releases/download/jq-${JQ_VERSION}/jq-linux-amd64" -o /usr/local/bin/jq
gh attestation verify /usr/local/bin/jq --repo jqlang/jq
sudo chmod +x /usr/local/bin/jq
jq --version # jq-1.8.2

Version 1.8.2 fixes more than a dozen CVEs (buffer and stack overflows triggered by malicious JSON input). On a script that processes untrusted JSON, prefer it to the 1.7.x versions still shipped by some repositories.

The API used in this guide

To illustrate each jq command concretely, we use the public JSONPlaceholder API. It is a free API that simulates the features of a REST service, ideal to practise without having to set up a backend.

Why this API?

  • It returns realistic JSON data: users, posts, comments, etc.
  • It is accessible without authentication.
  • The responses are consistently structured, perfect to learn how to handle JSON objects and arrays.

We will rely in particular on these two endpoints:

  • https://jsonplaceholder.typicode.com/users: to handle a list of users.
  • https://jsonplaceholder.typicode.com/posts: to work with posts and filter content.

Every request is made with curl and processed with jq, straight on the command line. This way, you can reproduce each command in your own terminal, without a complex installation.

Basic syntax

jq is mainly used in two ways: by reading a JSON file or by processing a data stream on standard input (stdin). Both methods are interchangeable depending on the context.

Read a JSON file

The classic syntax passes a JSON file as an argument:

Terminal window
jq '.' fichier.json

Here, the . filter means "print everything". This command prints the JSON content with a clean indentation, which makes it easier to read.

Read from standard input (stdin)

jq can also read directly from a stream, such as the one produced by a curl command:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.'
[
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere@april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
},
...
]

In this case, jq receives the JSON data through the | pipe, interprets it and formats it on screen.

Extracting specific data

With jq, you can extract precisely the elements you are interested in from a JSON structure. Here is how to do it from the JSONPlaceholder API, which returns a list of users.

Extract a simple key

Let us print every user's name with the .[].name filter:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[].name'
"Leanne Graham"
"Ervin Howell"
"Clementine Bauch"
"Patricia Lebsack"
"Chelsey Dietrich"
"Mrs. Dennis Schulist"
"Kurtis Weissnat"
"Nicholas Runolfsdottir V"
"Glenna Reichert"
"Clementina DuBuque"

The .[].name filter means: "in each element of the main array, print the name key".

Extract several keys

For each user, you can extract several pieces of information at once by building a new object:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[] | {id: .id, nom: .name, email: .email}'
{
"id": 1,
"nom": "Leanne Graham",
"email": "Sincere@april.biz"
}
{
"id": 2,
"nom": "Ervin Howell",
"email": "Shanna@melissa.tv"
}
{
"id": 3,
"nom": "Clementine Bauch",
"email": "Nathan@yesenia.net"
}
{
"id": 4,
"nom": "Patricia Lebsack",
"email": "Julianne.OConner@kory.org"
}
{
"id": 5,
"nom": "Chelsey Dietrich",
"email": "Lucio_Hettinger@annie.ca"
}
{
"id": 6,
"nom": "Mrs. Dennis Schulist",
"email": "Karley_Dach@jasper.info"
}
{
"id": 7,
"nom": "Kurtis Weissnat",
"email": "Telly.Hoeger@billy.biz"
}
{
"id": 8,
"nom": "Nicholas Runolfsdottir V",
"email": "Sherwood@rosamond.me"
}
{
"id": 9,
"nom": "Glenna Reichert",
"email": "Chaim_McDermott@dana.io"
}
{
"id": 10,
"nom": "Clementina DuBuque",
"email": "Rey.Padberg@karina.biz"
}

Here is what the command does in detail:

  1. curl -s https://jsonplaceholder.typicode.com/users This command sends an HTTP GET request to the JSONPlaceholder API. The -s flag means "silent", so curl does not show the progress bar. The result is a JSON array containing 10 users.

  2. jq '.[]' This filter tells jq: "Walk through each element of the array". It means that jq processes each user one by one.

  3. | {id: .id, nom: .name, email: .email} For each user, jq creates a new JSON object made only of three keys:

    • id → the value of the .id field (user identifier)
    • nom → the value of the .name field
    • email → the value of the .email field

This kind of transformation is perfect to simplify the display, extract targeted data, or prepare an export to another tool.

Extract a nested key

Let us print the name and the city of each user, a nested field:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[] | {nom: .name, ville: .address.city}'
{
"nom": "Leanne Graham",
"ville": "Gwenborough"
}
{
"nom": "Ervin Howell",
"ville": "Wisokyburgh"
}
{
"nom": "Clementine Bauch",
"ville": "McKenziehaven"
}
{
"nom": "Patricia Lebsack",
"ville": "South Elvis"
}
{
"nom": "Chelsey Dietrich",
"ville": "Roscoeview"
}
{
"nom": "Mrs. Dennis Schulist",
"ville": "South Christy"
}
{
"nom": "Kurtis Weissnat",
"ville": "Howemouth"
}
{
"nom": "Nicholas Runolfsdottir V",
"ville": "Aliyaview"
}
{
"nom": "Glenna Reichert",
"ville": "Bartholomebury"
}
{
"nom": "Clementina DuBuque",
"ville": "Lebsackbury"
}

.address.city gives access to a property nested in an "address" object.

Extract an element by its index

To get the data of the 3rd user, use an index between brackets:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[2]'
{
"id": 3,
"name": "Clementine Bauch",
"username": "Samantha",
"email": "Nathan@yesenia.net",
"address": {
"street": "Douglas Extension",
"suite": "Suite 847",
"city": "McKenziehaven",
"zipcode": "59590-4157",
"geo": {
"lat": "-68.6102",
"lng": "-47.0653"
}
},
"phone": "1-463-123-4447",
"website": "ramiro.info",
"company": {
"name": "Romaguera-Jacobson",
"catchPhrase": "Face to face bifurcated interface",
"bs": "e-enable strategic applications"
}
}

JSON arrays start at index 0. .[2] therefore targets the 3rd element.

Access a field of a specific element

Extract only the email of the 5th user by combining index and key:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[4].email'

You can combine indexes with key names to navigate the structure.

Tip for field names with dashes

If a field contains a special character, use double quotes after the . operator, otherwise jq reads the dash as a subtraction:

Terminal window
jq '."nom-du-champ"' fichier.json

Even if this case does not occur in JSONPlaceholder, it is good to know for other APIs.

Filters and transformations

The https://jsonplaceholder.typicode.com/users endpoint returns a list of 10 users, each with fields such as id, name, email, and an address object containing city, zipcode, etc. Here is how to transform this data with jq.

Select some users with select

Let us filter the users living in the city of "McKenziehaven" with select, which keeps the matching objects:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[] | select(.address.city == "McKenziehaven")'

The select(.address.city == "McKenziehaven") filter only prints the users matching this criterion.

Delete a field with del

Let us remove the full addresses of the users with del, which drops a key:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[] | del(.address)'

This command deletes the address field from each user object.

Rename and reorder fields

Let us build a simplified view with custom field names:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[] | {identifiant: .id, nom: .name, ville: .address.city}'

Here, we create a new object with renamed keys and an extracted sub-field.

Add a static field

Let us add a statut key to every user with the + operator, which merges two objects:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[] | . + {statut: "actif"}'

Each user object now contains a statut key with the value "actif".

Count the number of users

To get the total number of entries in the JSON response, use length:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq 'length'

The length filter counts the objects of the array.

Extract an array of values with map

Let us fetch a list of the emails with map, which returns an array:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq 'map(.email)'

This filter returns an array containing only the email addresses of the users.

Advanced use of jq

Once the basics are mastered, jq goes much further thanks to advanced filters, logical combinations and built-in functions. Here are a few powerful uses, still with the https://jsonplaceholder.typicode.com/users endpoint.

Combine several conditions with and / or

Let us filter the users whose ID is greater than 5 and who live in the city of "Howemouth":

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[] | select(.id > 5 and .address.city == "Howemouth")'

With and, jq evaluates several conditions on the same object. You can also use or:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[] | select(.id < 3 or .address.city == "Lebsackbury")'

Apply a function to a string or a number

Get every name in uppercase with ascii_upcase, a string function:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[] | {nom_majuscule: (.name | ascii_upcase)}'

Here, ascii_upcase converts the value of .name to uppercase.

Filter on a contained value (with contains)

Find the users whose name contains "Glen" with contains inside a select:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[] | select(.name | contains("Glen"))'

contains is case-sensitive. To ignore case, combine it with ascii_downcase, which normalises the string first:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[] | select((.name | ascii_downcase) | contains("glen"))'

Sort the data (local sort)

You can sort the users by name with sort_by, applied to the whole array:

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq 'sort_by(.name)[] | {id, nom: .name}'

sort_by(.name) sorts the array in alphabetical order on .name.

List of built-in functions

jq offers a rich collection of built-in functions to manipulate JSON data on the command line. These functions cover operations on strings, arrays, objects, numbers, types, and much more. Here is an overview of the main categories of functions available:

String functions

These functions work on text values, the most frequent case in an API response.

  • length: returns the length of a string.
  • ascii_upcase / ascii_downcase: converts a string to uppercase or lowercase.
  • split / join: splits a string into an array or joins an array into a string.
  • startswith / endswith: checks whether a string starts or ends with a given substring.
  • contains: checks whether a string contains a specific substring.

Array functions

These functions take an array as input, typically the list returned by an endpoint.

  • map: applies a transformation to each element of an array.
  • select: filters the elements of an array on a condition.
  • add: adds up the elements of a numeric array.
  • sort / sort_by: sorts the elements of an array.
  • unique / unique_by: removes duplicates from an array.
  • reverse: reverses the order of the elements of an array.

Object functions

These functions work on the keys of an object rather than on its values.

  • keys: returns the keys of an object.
  • has: checks for the presence of a key in an object.
  • del: deletes a key from an object.
  • to_entries / from_entries: converts an object into an array of key/value pairs and back.
  • with_entries: transforms the key/value pairs of an object

Mathematical functions

These functions apply to numbers, or turn a string into one.

  • floor / ceil / round: rounds a number down, up or to the nearest integer.
  • sqrt: computes the square root of a number.
  • tonumber: converts a string into a number.

Type and conversion functions

These functions tell or change the JSON type of a value.

  • type: returns the JSON type of a value (string, number, object, etc.).
  • tostring: converts a value into a string.
  • isfinite / isnan / isinfinite: checks properties of a number.

Traversal and recursion functions

These functions walk a structure at any depth, without knowing its shape.

  • recurse: walks a JSON structure recursively.
  • walk: applies a function to each element of a JSON structure.
  • paths / getpath / setpath: works with the paths in a JSON structure.

Control-flow functions

These constructs drive the flow of a filter: condition, error, empty output.

  • if / then / else / end: conditional structure.
  • try / catch: error handling.
  • empty: produces no output, useful to filter elements out.

Miscellaneous functions

These functions generate values or read additional inputs.

  • range: generates a sequence of numbers.
  • error: raises a custom error.
  • input / inputs: reads additional inputs.

For a complete and detailed list of jq's built-in functions, check the official documentation: https://jqlang.org/manual/

Here are some new concrete examples of advanced built-in functions of jq, still from the https://jsonplaceholder.typicode.com/users endpoint, and not covered above:

A few advanced examples

Each example below is followed by what it produces, on the first user or on the whole list.

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[] | {id_texte: (.id | tostring)}'

→ Converts the numeric id field into text, useful for concatenations or specific formats.

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[] | {nom: (.name | type), adresse: (.address | type)}'

→ Prints the data types (string, object, etc.) of given fields.

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[0] | with_entries(.key |= ascii_upcase)'

→ Puts every key of the first user in uppercase.

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[0] | to_entries | map(.key += "_mod") | from_entries'

→ Renames every key of the first user by adding a _mod suffix.

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[0] | recurse(.[]? | select(type == "object"))'

→ Explores every nested object of the first user recursively.

Terminal window
curl -s https://jsonplaceholder.typicode.com/users | jq '.[0] | walk(if type == "string" then ascii_downcase else . end)'

→ Puts every string in lowercase in the first user, whatever its depth.

Key points

  • jq reads JSON from a file or a stream (curl ... | jq '.')
  • Extract: .[], .key, nested field .address.city, index .[2]
  • Filter: select(...), contains, and / or conditions
  • Transform: map, del, objects {...}, sort_by sort
  • jq is compact, fast and dependency-free: ideal in scripts and CI/CD pipelines

Knowledge check

Check that the essentials of this guide are acquired. The questions only cover what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

6 questions
6 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

The official manual lists every filter, and the online playground lets you test a filter without installing anything:

FAQ: frequently asked questions

The answers below go further than the page, with DevOps examples on Kubernetes, AWS and Terraform outputs.

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn