duckdb-jq
May 20, 2026 · View on GitHub
A DuckDB extension that exposes jq as a scalar SQL function, letting you directly run jq filters on JSON values in SQL queries.
The extension links libjq (with its bundled oniguruma regex engine) statically, so no external jq binary is required at runtime.
This repository is based on https://github.com/duckdb/extension-template.
Installation
- TODO: Set up distribution / installation instructions
Functions
jq(input JSON, filter VARCHAR, allow_multiple BOOLEAN := false) → JSON
Run the given jq filter against the given input expression, expecting at most one result per input value.
Important
If filter yields more than one JSON value, an error is raised at execution time.
If you wish to return multiple results per input, wrap your filter in array brackets: [ ... ].
Parameters:
input— a JSON valuefilter— a jq filter; must be a constant expression (it's compiled once at bind time and reused across rows)
Return value:
- If filter yields a single JSON value (including JSON-
null!), returns that value. - If filter yields no value (i.e.
empty), returns SQLNULL.
Additional error cases:
- If input is not valid JSON, an error is raised at execution time.
- If filter string is not valid jq syntax, an error is raised at bind time.
// TODO: unnest_multiple keyword argument
to "unnest" multiple results; so select foo, bar, jq(<...>, unnest_multiple:=true) as blah, baz behaves similarly to jq's own behavior for e.g. jq '{ foo, bar, blah: <...>, baz }'
// TODO: jq_agg aggregate function
Filter receives all JSON inputs from each group as a "slurped" array, and is expected to output one value.
Examples
-- Pick a single value
SELECT jq('{"a": 1, "b": [10,20,30]}', '.b[1]');
-- 20
-- More complicated filter
SELECT jq('{"a": 1, "b": [10,20,30]}', '[ {a} + {b: .b[]} ]');
-- [{"a":1,"b":10},{"a":1,"b":20},{"a":1,"b":30}]
-- Built-in jq functions, including oniguruma-backed ones
SELECT jq('{"name": "alice"}', '.name | ascii_upcase');
-- "ALICE"
-- Empty results become SQL NULL
SELECT jq('1', 'empty') IS NULL;
-- true
-- Apply a fixed filter across a column of JSON values
SELECT jq(j, '.x') FROM (VALUES ('{"x":1}'), ('{"x":2}')) t(j);
-- 1
-- 2
Building
The jq source lives in the ./jq submodule and is built via its own autotools build. Linux, macOS, and Windows (MinGW via rtools42/MSYS2) are supported; MSVC Windows builds are not (jq has no MSVC support upstream). Make sure submodules are initialized:
git submodule update --init --recursive
Then build:
make
The main binaries produced are:
./build/release/duckdb
./build/release/test/unittest
./build/release/extension/jq/jq.duckdb_extension
duckdbis the DuckDB shell with the extension preloaded.unittestis the DuckDB test runner with the extension linked in.jq.duckdb_extensionis the loadable binary as it would be distributed.
Running the extension
Start the shell with the extension preloaded:
./build/release/duckdb
Then use jq(...) directly in SQL — see the examples above.
Running the tests
SQL tests live in ./test/sql. Run them with:
make test