Skip to content
Latchkey

jq --arg and --argjson : Pass Shell Values In

jq --arg name value binds a string variable; --argjson name value binds a value parsed as JSON.

Injecting a branch name, a number, or a JSON array from the shell into a jq filter safely is what --arg and --argjson are for in CI.

What it does

--arg name value binds $name to the value as a string, never interpreted as JSON, which avoids injection. --argjson name value parses the value as JSON first, so use it for numbers, booleans, arrays, and objects. Both are safer than interpolating into the program text.

Common usage

Terminal
# filter by a shell-provided string safely
jq --arg branch "$BRANCH" '.[] | select(.name == $branch)' branches.json
# pass a number as JSON, not a string
jq --argjson min 100 '.[] | select(.size > $min)' files.json
# pass an array
jq --argjson tags '["a","b"]' '.[] | select(.tag | IN($tags[]))' items.json

Flags

FlagWhat it does
--arg n vBind $n to v as a string
--argjson n vBind $n to v parsed as JSON
--slurpfile n fBind $n to an array of values from file f
--rawfile n fBind $n to the raw contents of file f

In CI

Always pass user or environment data through --arg/--argjson rather than splicing it into the program string; this prevents a value with quotes or special characters from breaking or hijacking the filter. Use --argjson for anything that should stay a number, boolean, or array.

Common errors in CI

"jq: Invalid JSON text passed to --argjson" means the value is not valid JSON, often an unquoted string that needed --arg instead. "jq: error: $x is not defined" means the program uses $x but no matching --arg was given. A numeric comparison that always fails usually means a number was passed with --arg (as a string) rather than --argjson.

Using this in CI

A runner shell is not a login shell. It does not read your dotfiles, it usually has no TTY, and by default it does not stop on the first error, so a failing command in the middle of a multi-line run block can leave the job green.

.github/workflows/ci.yml
# make the shell behave the way you assume it does
- name: Build
  shell: bash
  run: |
    set -euo pipefail    # exit on error, undefined vars, and pipeline failures
    ./do-the-thing | tee out.log

Frequently asked questions

jq --arg and --argjson : Pass Shell Values In?
Injecting a branch name, a number, or a JSON array from the shell into a jq filter safely is what --arg and --argjson are for in CI.
What it does?
--arg name value binds $name to the value as a string, never interpreted as JSON, which avoids injection. --argjson name value parses the value as JSON first, so use it for numbers, booleans, arrays, and objects. Both are safer than interpolating into the program text.
In CI?
Always pass user or environment data through --arg/--argjson rather than splicing it into the program string; this prevents a value with quotes or special characters from breaking or hijacking the filter. Use --argjson for anything that should stay a number, boolean, or array.
Common errors in CI?
"jq: Invalid JSON text passed to --argjson" means the value is not valid JSON, often an unquoted string that needed --arg instead. "jq: error: $x is not defined" means the program uses $x but no matching --arg was given.

Related guides

References

Run this faster and cheaper on Latchkey managed runners - self-healing included. Start free → 30-day trial · No credit card