How to Reuse jq Filters with import, include, and -f

All jq tools and guides

To reuse a jq filter, choose between an inline def (one program), a saved program with -f (run the same program again), or a module with import or include (share functions between different programs). The examples first show jq CLI syntax, then show how a Java application can reuse the same files. The browser playground accepts inline definitions but does not load module files.

For the examples below, save this input as input.json:

{"name":"Ada"}

Each command outputs "ADA".

Define a helper in one filter

jq 'def display_name: .name | ascii_upcase; display_name' input.json

def gives part of a filter a name. The definition is available inside this jq program, but a separate jq command will not inherit it. In the browser jq playground, put both the def and the expression that calls it in the filter editor.

Save and rerun a whole program with -f

Save filter.jq:

def display_name: .name | ascii_upcase;
display_name

Then run it against any compatible JSON input:

jq -f filter.jq input.json

-f reads the entire jq program from filter.jq instead of a quoted command-line filter. It does not automatically make its definitions available to other jq files. A runnable program needs a final expression after its def statements; filter.jq ends with display_name.

Share functions between jq programs with import

Save only the reusable definition in helpers.jq:

def display_name: .name | ascii_upcase;

Import it into a command-line filter under a namespace:

jq -L . 'import "helpers" as h; h::display_name' input.json

-L . tells jq to look for modules in the current directory. The import name omits .jq; import "helpers" as h loads helpers.jq, and h::display_name calls its function. A second program can reuse the same module without copying the definition:

import "helpers" as h;
{label: h::display_name}

Save this program as label.jq, then run jq -L . -f label.jq input.json to get {"label":"ADA"}. Use a project directory in place of . when modules are stored elsewhere. A missing module or function is a jq error, not a fallback to an empty result.

Use include for an unqualified function name

If you do not need a namespace, the same helpers.jq also works with:

jq -L . 'include "helpers"; display_name' input.json

include makes display_name available without the h:: prefix. Prefer import ... as h when multiple modules might define the same name; include is convenient for a small shared helper library.

Reuse the same files from Java or another application

If your application invokes the jq executable, pass arguments directly rather than building a shell command string. For example, with helpers.jq, label.jq, and input.json from above in the Java process's working directory:

import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class RunJq {
    public static void main(String[] args) throws IOException, InterruptedException {
        Process process = new ProcessBuilder(
            "jq", "-L", ".", "-f", "label.jq", "input.json"
        ).redirectErrorStream(true).start();
        String output = new String(process.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
        int exitCode = process.waitFor();
        if (exitCode != 0) {
            throw new IllegalStateException("jq exited " + exitCode + ": " + output);
        }
        System.out.print(output);
    }
}

This prints {"label":"ADA"} (jq may add spaces in its JSON output). The application needs jq installed on its PATH; -L still controls module lookup, and -f still loads the main program. ProcessBuilder does not invoke a shell here, so no shell quoting or interpolation is needed.

If instead you use an in-process jq library that accepts filter source text, the portable option is to read a shared definition and append a final expression before giving the resulting source to that library:

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

String source = Files.readString(Path.of("helpers.jq"), StandardCharsets.UTF_8)
    + "\ndisplay_name";
// Pass source and your JSON input to your jq library's compile/evaluate API.

This produces the same jq program as the inline def example, without depending on the library's module loader. The last line is an integration step, not a universal Java jq API: libraries differ in how they compile filters and supply input. If your library supports module resolution, configure its module search path and use import/include instead; CLI switches like -L and -f are not automatically available inside an embedded library. Do not concatenate untrusted input into jq source; pass values through your library's argument/input API.

The CLI examples above were verified with jq 1.8.1. -f loads a program and -L selects where import/include find modules; they solve different reuse needs and can be combined. If you want to pass data rather than code, use --arg or --argjson to pass shell values instead. The jq cheatsheet covers more filter syntax. Reference: jq manual, invoking jq and jq modules.