---
title: "jq Syntax Cheatsheet"
slug: "jq-syntax"
category: "cheatsheets"
tags: ["cheatsheets", "jq", "json", "cli", "reference", "data-processing"]
status: "stable"
last_updated: 2026-05-14
summary: "jq selectors, filters, transformations, map/select, common one-liners, and null handling: the expressions worth memorizing for command-line JSON work."
related:
  [
    "[[cheatsheets/bash-one-liners]]",
    "[[cheatsheets/curl-flags]]",
    "[[cheatsheets/gh-cli]]",
    "[[cheatsheets/find-grep-awk-sed]]",
    "[[backend/postgres-jsonb]]",
    "[[cheatsheets/index|Cheatsheets]]",
  ]
---

## Overview

`jq` is the standard tool for slicing, filtering, and transforming JSON on the command line. This card covers the expressions you reach for every day. For querying JSON inside Postgres, see [[backend/postgres-jsonb]]. For using `jq` with API responses, see [[cheatsheets/curl-flags]].

All examples use this input unless stated otherwise:

```json
[
  {"name": "alice", "age": 30, "tags": ["admin", "user"]},
  {"name": "bob",   "age": 25, "tags": ["user"]},
  {"name": "carol", "age": 35, "tags": ["admin"]}
]
```

## Selectors

Access fields and array elements.

| Expression | Result |
| --- | --- |
| `.` | Identity; pass input through unchanged. |
| `.name` | Field `name` from an object. |
| `.["user-name"]` | Field with special characters in name. |
| `.[0]` | First element of an array. |
| `.[-1]` | Last element. |
| `.[2:5]` | Slice from index 2 to 4. |
| `.[]` | Iterate array or object values. |
| `.foo.bar` | Chained field access. |
| `.foo?.bar` | Optional: suppress errors if `.foo` is null or missing. |
| `keys` | Array of object keys. |
| `values` | Array of object values. |
| `length` | Length of array, string, or object. |
| `has("name")` | True if key exists. |
| `in({"a":1})` | True if the input is a key in the object. |

Use `?` to suppress `null` errors when a field might not exist.

## Filters and transforms

Shape and transform data.

| Expression | Result |
| --- | --- |
| `.[].name` | `"alice"`, `"bob"`, `"carol"` (one per line). |
| `[.[].name]` | `["alice","bob","carol"]` (collect into array). |
| `{n: .name, a: .age}` | Build a new object. |
| `[.[] \| {n: .name}]` | Map to new objects. |
| `select(.age > 28)` | Keep only matching elements. |
| `[.[] \| select(.age > 28)]` | Filter array. |
| `sort_by(.age)` | Sort array by field. |
| `sort_by(.age) \| reverse` | Sort descending. |
| `group_by(.age)` | Group into arrays by field value. |
| `unique_by(.name)` | Deduplicate by field. |
| `min_by(.age)` / `max_by(.age)` | Min or max element. |
| `add` | Sum numbers, concatenate strings/arrays, merge objects. |
| `flatten` | Recursively flatten nested arrays. |
| `to_entries` | Convert object to `[{key, value}]` pairs. |
| `from_entries` | Convert `[{key, value}]` pairs back to object. |
| `with_entries(.value += 1)` | Map over object entries. |

## Piping and composition

Chain expressions with `|`; assign intermediate values with `as`.

| Expression | Result |
| --- | --- |
| `.[] \| .name` | Stream names. |
| `.[] \| select(.age > 28) \| .name` | Filtered names. |
| `[.[] \| .age] \| add / length` | Average age. |
| `. as $input \| ...` | Bind input to variable for reuse. |
| `(.a, .b)` | Multiple outputs from one expression. |
| `if .age > 30 then "senior" else "junior" end` | Conditional. |
| `try .foo catch "missing"` | Handle errors gracefully. |
| `@base64` | Base64-encode a string. |
| `@json` | Serialize to JSON string. |
| `@csv` | Format an array as CSV. |
| `@tsv` | Format an array as TSV. |
| `@uri` | URL-encode a string. |
| `@html` | HTML-escape a string. |

## map and select patterns

`map` applies an expression to every element; `select` filters elements.

| Pattern | Result |
| --- | --- |
| `map(.age \| . * 2)` | Double every age. |
| `map(select(.age > 28))` | Filter array inline (equivalent to `[.[] \| select(...)]`). |
| `map(.tags[])` | Flatten nested arrays one level. |
| `[.[] \| .tags[]]` | All tags across all users. |
| `[.[] \| .tags[] \| select(. == "admin")]` | All occurrences of `"admin"`. |
| `map(select(.tags \| contains(["admin"])))` | Users with "admin" tag. |
| `map(.name) \| sort \| unique` | Sorted unique names. |
| `reduce .[] as $u (0; . + $u.age)` | Sum ages with reduce. |

## Common one-liners

Ready-to-paste expressions for frequent tasks.

| Task | jq expression |
| --- | --- |
| Pretty-print | `jq '.'` |
| Compact output | `jq -c '.'` |
| Raw string output | `jq -r '.name'` |
| Count items | `jq 'length'` |
| First match | `jq 'first(.[] \| select(.age > 28))'` |
| Pluck fields | `jq '[.[] \| {name, age}]'` |
| Merge two objects | `jq -n '$a * $b' --argjson a '{"x":1}' --argjson b '{"y":2}'` |
| Pass shell var | `jq --arg name "$NAME" '.[] \| select(.name == $name)'` |
| Null fallback | `jq '.foo // "default"'` |
| Recursive descent | `jq '.. \| .id? \| values'` |

Use `jq -r` when the output feeds a shell variable; without `-r` the value is quoted JSON.

## Common gotchas

- `.foo` returns `null` for a missing key, not an error. Use `has("foo")` or `if .foo then` to distinguish missing from null.
- `//` is the alternative operator: `.foo // "default"` returns `"default"` only when `.foo` is `false` or `null`. It does not protect against missing keys returning `null`.
- `.[].foo` streams values; wrap in `[...]` to collect them into an array. Forgetting the brackets means the output is multiple JSON values, not a JSON array.
- `jq -r` on an array output still prints the array brackets. Use `jq -r '.[]'` to get raw lines.
- The pipe inside a `map(...)` applies to each element; a pipe outside `map` applies to the whole array. `map(. + 1)` adds 1 to each; `map(.) | add` concatenates or sums the whole array.
- `sort_by` requires comparable types. Mixed-type arrays (numbers and strings) cause an error.

## Related

- [[cheatsheets/curl-flags]]
- [[cheatsheets/bash-one-liners]]
- [[cheatsheets/gh-cli]]
- [[cheatsheets/find-grep-awk-sed]]
- [[backend/postgres-jsonb]]
- [[cheatsheets/index|Cheatsheets]]
