Query Nickel files with nickel expressions. Top-level fields are automatically in scope — no import boilerplate needed.
# Count rows
nclq 'rows |> std.array.length' cog_tabulation.ncl
# => 357
# Filter + project + limit
nclq 'rows' cog_tabulation.ncl --where agg_level=1 --fields cogcs,description --limit 5
# Unique values
nclq 'rows' cog_tabulation.ncl --unique agg_level
# => [1, 2, 3, 4, 5, 6, 7]
# Inspect file structure
nclq rules_user.ncl --list-fields --depth 2Requires nickel on $PATH and an OCaml toolchain (opam, dune).
git clone <repo-url> && cd nickel-query
dune build
scripts/install.sh # copies binary to ~/.local/bin/nclqnclq [OPTIONS] <EXPR> [FILE]
nclq [OPTIONS] <EXPR> -f <NAME>=<FILE> [-f ...]
nclq [OPTIONS] <FILE> # defaults expression to _file
... | nclq [OPTIONS] <EXPR> # reads nickel from stdin
The expression is standard nickel — std.array.filter, std.array.map, |>, pattern matching, everything the stdlib provides. nclq removes the ceremony of let data = import "..." in wrappers.
Top-level record fields are bound directly into scope:
nclq 'rows |> std.array.filter (fun r => r.score > 10)' data.ncl
nclq 'metadata' data.ncl --rawEach file is bound to a name with -f:
nclq 'tab.rows |> std.array.length' \
-f tab=cog_tabulation.ncl -f cb=cog_codebook.nclecho '{ x = 1, y = 2 }' | nclq 'x + y'Flags compose with the expression result. When combined, they apply in this fixed order:
where → sort-by → unique → fields → limit → count
Filter array elements. Operators: = != > < >= <= ~ (contains). Repeatable — multiple clauses are ANDed. Value types are auto-detected from data.
nclq 'rows' data.ncl --where 'score>10'
nclq 'rows' data.ncl --where agg_level=1 --where 'description~Revenue'Sort by a field. Comparator (numeric vs string) is auto-detected from data.
nclq 'rows' data.ncl --sort-by score --desc --limit 3Extract deduplicated values of a field.
nclq 'rows' data.ncl --unique categoryReturn array length instead of data.
nclq 'rows' data.ncl --where 'score>10' --countList field names. For arrays, inspects the first element. --depth N recurses into nested records.
nclq data.ncl --list-fields
nclq config.ncl --list-fields --depth 3Project named fields and truncate arrays.
nclq 'rows' data.ncl --fields id,name --limit 10nclq 'rows' data.ncl --format json # JSON output
nclq 'metadata' data.ncl --raw # strip quotes
nclq 'std.array.first rows' data.ncl --compact # single linenclq generates nickel code and delegates evaluation to the nickel binary:
- Parse CLI args
- Discover top-level field names (preliminary
std.record.fieldseval) - Discover field types when needed (preliminary
std.record.mapeval) - Generate nickel program with imports, bindings, and flag wrappers
- Pipe to
nickel evalornickel export - Post-process output (--raw, --compact)
The tool is written in OCaml with cmdliner for CLI parsing. No nickel embedding — it shells out to the nickel binary on $PATH.
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Nickel evaluation error |
| 2 | Invalid arguments |
| 127 | nickel not found on $PATH |