How to Convert JSON Data to CSV in Linux Terminal Using jq

Modern APIs, logging frameworks, and cloud utilities frequently return structured data formatted as JSON. However, business reporting, spreadsheet applications like Excel and Calc, and traditional command-line utilities such as awk and cut often work best with flat comma-separated values (CSV). The lightweight command-line JSON processor jq provides built-in format filters, specifically the @csv operator, allowing administrators and developers to parse and convert nested JSON streams into clean CSV files directly within Linux terminal pipelines.

Installing jq on Linux Distributions

Before running conversions, verify that jq is installed on your Linux system. Most modern distribution repositories maintain up-to-date versions of the utility:

  • Debian, Ubuntu, and Linux Mint:
    sudo apt update && sudo apt install -y jq
  • RHEL, CentOS, Rocky Linux, and Fedora:
    sudo dnf install -y jq
  • Arch Linux and Manjaro:
    sudo pacman -S jq

Converting a Flat JSON Array to CSV

Consider a simple JSON array representing a list of user accounts saved in a file named users.json:

[
  {"id": 101, "name": "Alice Smith", "role": "DevOps Engineer", "active": true},
  {"id": 102, "name": "Bob Jones", "role": "System Administrator", "active": false},
  {"id": 103, "name": "Charlie Brown", "role": "Security Analyst", "active": true}
]

To convert this array into a CSV format with column headers, pass the array through jq using the -r (raw output) flag. The raw output flag is critical because it tells jq to emit actual unescaped CSV strings rather than wrapping every row inside JSON quotation marks:

jq -r '["ID", "Name", "Role", "Active"], (.[] | [.id, .name, .role, .active]) | @csv' users.json > users.csv

Here is how this command constructs the output:

  • ["ID", "Name", "Role", "Active"]: Defines a static array of column header names that forms the very first line of the CSV.
  • ,: The comma operator branches the stream, evaluating both the header array and the following data expressions sequentially.
  • .[]: Iterates over each object element inside the root array.
  • [.id, .name, .role, .active]: Constructs an ordered array containing the specific field values extracted from each object.
  • | @csv: Passes each constructed array into the built-in CSV formatter, which automatically handles double quotes, escaping commas, and separating fields.

The resulting users.csv file will contain:

"ID","Name","Role","Active"
101,"Alice Smith","DevOps Engineer",true
102,"Bob Jones","System Administrator",false
103,"Charlie Brown","Security Analyst",true

Handling Nested Objects and Missing Keys

Real-world API payloads often contain deeply nested structures or missing fields. If a key is missing from a JSON object, referencing it directly can cause runtime errors or misaligned table columns.

Consider an API response with nested contact information:

[
  {"id": 1, "name": "David", "contact": {"email": "[email protected]", "phone": "555-0192"}},
  {"id": 2, "name": "Eva", "contact": {"email": "[email protected]"}}
]

To safely extract nested values and substitute empty strings or default placeholders for missing keys, use optional chaining and the alternative operator (//):

jq -r '["ID", "Name", "Email", "Phone"], (.[] | [.id, .name, (.contact.email // ""), (.contact.phone // "N/A")]) | @csv' data.json

Converting Streaming Newline-Delimited JSON (NDJSON)

Many logging agents and database exports output Newline-Delimited JSON (where each individual line is a standalone JSON object rather than elements in a single enclosing bracket array). When handling NDJSON files, do not use the array iterator .[] because the root level is not an array:

jq -r '["Timestamp", "Level", "Message"], ([.time, .level, .msg]) | @csv' server.ndjson > server_logs.csv

Converting to Tab-Separated Values (TSV)

If your workflow requires tab-delimited files rather than comma-delimited output (common when piping directly into Unix utilities like awk or cut), simply replace the @csv filter with @tsv:

jq -r '["ID", "Name", "Role"], (.[] | [.id, .name, .role]) | @tsv' users.json > users.tsv

The @tsv filter formats each array element with tab separators, preserving clean text processing across all shell scripts without requiring external regex transformations.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.