Query Nickel files with nickel expressions.
Top-level fields are automatically in scope — no import boilerplate. Write the expression, point at the file, get the result.
# Count rows — no imports, no jq
nclq 'rows |> std.array.length' cog_tabulation.ncl
# => 357
# Filter + project
nclq 'rows' data.ncl --where 'score>10' --fields id,name --limit 5
# Unique values
nclq 'rows' data.ncl --unique category
# Inspect nested config
nclq config.ncl --list-fields --depth 2
Requires nickel on $PATH and an OCaml toolchain.
dune build && scripts/install.sh
Installs to ~/.local/bin/nclq.
nclq generates nickel code and pipes it to nickel eval.
In single-file mode, it discovers top-level fields and binds them into scope.
Built-in flags (--where, --sort-by, etc.) generate additional nickel wrapping code.
Type discovery uses a preliminary eval so --where score>10 knows score is a number.
Flags compose with the expression result in a fixed pipeline:
where → sort-by → unique → fields → limit → count
| Flag | Purpose |
|---|---|
--where COND | Filter: field=val, field>val, field~substr. Repeatable, ANDed. |
--sort-by FIELD | Sort by field. Type auto-detected. Add --desc for descending. |
--unique FIELD | Extract unique values of a field. |
--fields F1,F2 | Project named fields from records. |
--limit N | Truncate arrays to first N elements. |
--count | Return count instead of data. |
--list-fields | List field names. --depth N for nested. |
--format FMT | Output as nickel, json, yaml, or toml. |
--raw | Strip quotes from string output. |
--compact | Single-line output. |
-f NAME=FILE | Multi-file mode with named bindings. |
# View a file
nclq data.ncl --compact
# Filter rows where agg_level is 1 and description contains "Revenue"
nclq 'rows' cog_tabulation.ncl --where agg_level=1 --where 'description~Revenue'
# Top 3 by score, descending
nclq 'rows' data.ncl --sort-by score --desc --limit 3
# Count matching rows
nclq 'rows' data.ncl --where 'description~Education' --count
# Cross-reference two files
nclq 'tab.rows |> std.array.filter (fun r =>
std.array.elem r.id (cb.codes |> std.array.map (fun c => c.id)))' \
-f tab=tabulation.ncl -f cb=codebook.ncl
# Pipe from stdin
echo '{ x = 1, y = 2 }' | nclq 'x + y'
# JSON export for jq
nclq 'rows' data.ncl --where 'score>10' --format json | jq '.[].id'
The nickel CLI can evaluate, export, and typecheck .ncl files,
but it can't filter or inspect data without serializing to JSON and piping through jq.
In a research monorepo with nickel files exceeding 4,000 lines,
every ad-hoc query required a verbose pipeline:
nickel export --format json input.ncl | jq '[.rows[] | select(.item_code == null)]'
nclq replaces this with:
nclq 'rows' input.ncl --where 'item_code!=null'