Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

CLI reference

CommandResult
qk inputs analyze <task> [--report <path>] [--previous <path>] [--suggestions <path>]Execute tasks without caching, record file accesses and review input coverage; macOS, or Linux with eBPF or strace. See Recording task inputs
qk show projects [--json]Project names in Nx graph order, one per line or as a compact JSON array
qk show projects -p 'web,tag:library' --exclude 'experimental-*'Matching names, globs, tags and roots, minus exclusions
qk show projects --with-target e2e --type app [--sep ,]Projects with one of the targets, of a type (app, lib or e2e, as Nx types them), joined by a separator
qk show projects --affected -t build,exportProjects owning an affected task of one of the targets, or under project selection the affected projects with one of them, as qk affected selects them
qk show projects --affected --affected-targets build,exportAffected projects where a task of one of the targets is affected, as task selection decides it
qk show project [name] [--json]A project’s graph node, as Nx’s summary or one line of JSON; the current directory’s project by default, and a name that is no project matches as a pattern, as in Nx
qk graph --file <path>.jsonWorkspace project graph in a { "graph": { "nodes": ..., "dependencies": ... } } envelope
qk graph, qk graph --file stdout or --file -The same graph on stdout
qk graph --externalThe graph with the packages the pnpm lockfile installs as externalNodes
qk graph --focus web --exclude 'tag:e2e'Only web, what it depends on and what depends on it, minus exclusions
qk run <project>:<target>[:<configuration>], qk run -p <project> -t <target>Execute a task and its dependencies
qk <target> [project], qk <project>:<target>, qk <project>Nx-style shorthand for qk run
qk run-many -t build,test -p 'web,core' --parallel 4Execute matching targets with bounded task concurrency
qk exec -p web -- <command>Run a command in projects, or as a package script’s target, as nx exec does
qk run web:build --dry-runPrepare every planned task without running it, and print the task graph as JSON
qk show projects --affected [--base <rev>] [--head <rev>]Projects affected by the changes, in graph order
qk affected -t build,test [--base <rev>] [--head <rev>]Execute the affected tasks of the targets, and the tasks they depend on
qk show affected [project] [--json]Why projects are affected, or why one project is, and the granularity qk affected selects by
qk affected -t build --granularity projectExecute the targets of the affected projects, as affected.legacy does
qk show tasks -t build,test --affected [--json]The affected tasks and why
qk show runs, qk show run [id]Recent runs; one run’s tasks, cache results and critical path
qk show flaky [task]Mixed successful/failed executions for identical declared inputs
qk show log <run> <task>Replay retained stdout/stderr from an actual cacheable execution
qk show task <project:target>A task’s recent runs and why its cache key changed
qk show hash <project:target> [--against <task|run>]A task’s cache key and what it covers, or where it differs from another key, without running the task
qk cache pathPrint the local cache directory without creating it
qk cache prune [--max-size 1GB]Evict entries unused for a week, then least recently used entries until the cache fits
qk warm suggest <project:target>Run a task in the sandbox and list directories it wrote outside its outputs, as candidate warm paths (macOS)
qk reset [--only-cache | --only-workspace-data]Remove the cache and this worktree’s state, as nx reset does

As in Nx, qk build web and qk web:build mean qk run web:build, and take the same options. qk run reads its task as Nx’s run does: a project:target[:configuration], else -t/--target (for a target whose name has a colon) with -p/--project or the positional naming the project, else a project with a run target, which qk tool and qk run tool run, else a target. The project may be a name or a pattern matching exactly one project; a pattern matching several fails with Nx’s “Multiple projects matched”. As in Nx, b, e, l, s and t name the build, e2e, lint, serve and test targets. Without a project, qk build and qk run build use the project whose root most specifically contains the current directory, as Nx does: in the root project, NX_DEFAULT_PROJECT picks another, and where no project contains the directory, NX_DEFAULT_PROJECT, then nx.json cli.defaultProjectName, then defaultProject. As in Nx, --base, --head, --files, --uncommitted and --untracked imply --affected for show projects. qk’s own subcommands, and Nx commands qk does not implement such as format and release, are never read as targets; use qk run for a target with one of those names.

As in nx graph, --focus keeps the project and every project connected to it through dependencies in either direction, and --exclude takes project selectors. The kept projects’ edges are unchanged, so they can name projects left out. --print and --file stdout write to stdout. qk has no browser view, so nx graph’s --affected, --view and server options do not apply; for a task graph, use qk run-many -t <targets> --graph.

Options are read as Nx’s yargs configuration reads them. They may be spelled in camelCase as well as kebab-case, so Nx’s --outputStyle works as --output-style. A boolean option takes a value or a negation: --nx-bail=false, --skip-nx-cache true and --no-nx-bail all work, and any value other than true means false. An explicit --nx-bail=false or --verbose=false overrides NX_BAIL and NX_VERBOSE_LOGGING.

On the commands that run tasks, run and its shorthand, run-many and affected, an option qk does not know, and a positional beyond the command’s own, is forwarded to the requested tasks, as Nx’s unknown-options-as-args forwards it: qk test web --coverage runs web:test with --coverage. They are forwarded in order and as spelled, followed by any arguments after --, which are forwarded unchanged. Nx drops the unknown options when a -- is also given; qk keeps them. The other commands reject unknown options.

As in Nx, the hidden affected:build, affected:test, affected:lint and affected:e2e run affected for that target, and affected:graph and print-affected, which Nx removed, fail with Nx’s message.

--workspace <path> works before or after the subcommand. As in Nx, a graph --file path is relative to the workspace root, its directories are created, and it must end in .json; qk has no HTML graph, so a .html file fails. JSON output has no progress messages mixed into stdout. Errors go to stderr and return a nonzero exit code. Unknown commands fail explicitly.

exec

qk exec -- <command> runs a command as nx exec does. Each argument is wrapped in double quotes and the result runs in the shell tasks use, so $NAME expands; NX_PROJECT_NAME and NX_PROJECT_ROOT_PATH name the project.

  • Inside a task, where NX_TASK_TARGET_PROJECT is set, the command runs in the current directory for that project.
  • From a package script, where the package manager sets npm_lifecycle_event, the current directory’s project runs the script’s target instead, with the run options and any arguments beyond the script’s own. That task runs the script again, which then takes the first case, so a script such as "build": "qk exec -- tsc" is cached. Nx runs nx run for it without the run options, and reads the extra arguments as its own options; qk passes the options to the run and the arguments to the task.
  • Otherwise it runs in each project -p and --exclude select, all by default, and in every project they depend on, dependencies first. The first failure stops it. --exclude-task-dependencies runs only the selected projects.

The command is what follows --; as in Nx, other options exec does not know are ignored. A failing command exits with 1, as in Nx. Only the package-script case runs a task, so the others refuse --sandbox, --dry-run and --graph rather than run the command without them.

Shared run options

These options apply to run, run-many and affected:

OptionBehavior / default
-c, --configuration <name>Select named options; otherwise defaultConfiguration
--prodSelect production
--parallel [value]Number, percentage, or false; NX_PARALLEL, then workspace parallel, then 3
--cores <count>Positive core budget; QK_CORES, then qk:cores, then available cores
--skip-cacheBypass all result caching and warm state
--coldRun each task from scratch: restore no result and empty its warm paths rather than restore them, then save both as usual; QK_COLD=true too. See Replacing a bad save
--skip-remote-cacheKeep local caching only
--nx-bailStop starting tasks after the first failure; NX_BAIL=true too
--nx-ignore-cyclesDrop cycle-closing dependency edges with a warning
--exclude-task-dependenciesRun only requested tasks
--graph[=<file>]Write Nx-shaped project/task graph without execution; default stdout
--dry-runPrint qk’s task graph; no dotenv, runtime inputs or executor preflight
--output-style <style>Select output behavior; see Running tasks
--verboseSet NX_VERBOSE_LOGGING=true for tasks, which otherwise see false unless it is set to true; print every task in full under static-failures-only
--sandbox[=audit|enforce]Report (audit) or refuse (enforce) what tasks read and write in the workspace beyond their declarations. A task restored from the cache is not checked; add --skip-cache to check every one. See Checking inputs in a sandbox
--sandbox-report <path>Write every sandbox finding as JSON
--recordRecord what each task with qk:ultracache reads when it executes, and key its result by that; Linux only. With --sandbox, audit what it records. See Keying tasks by what they read and Auditing recorded runs
--report <path>Save JSON run report; defaults to NX_RUN_REPORT when set
--profilePrint cache input and restore phase timings to stderr; see Profiling cache operations
-- <args>Forward arguments to requested tasks, after any unknown options

--parallel alone uses NX_PARALLEL, otherwise 3. Percentages are rounded down with a minimum of one task. --skip-nx-cache and --disable-nx-cache alias --skip-cache, as NX_SKIP_NX_CACHE=true and NX_DISABLE_NX_CACHE=true do; --disable-remote-cache aliases --skip-remote-cache. The corresponding environment flags are documented in Environment variables.

Profiling cache operations

Run qk run web:build --profile (or set QK_PROFILE_CACHE=1) to print lines such as qk profile: task=web:build stage=local_restore ms=3.197. Profiling is disabled by default and reads no clocks while disabled.

Timings cover dependency inputs, declared inputs, runtime commands, remote fetches, local restore phases, restoring and saving warm state, the command itself (execute), the input recheck after it (inputs_recheck) and storing its result (publish). Input resolution also times listing the workspace’s files (inventory_list), waiting for another task’s listing (inventory_wait) and parsing pnpm-lock.yaml (lockfile_parse); each is charged to the task that needed it. A remote fetch also times waiting for the store’s index (remote_index_wait), waiting for the store to respond (remote_response) and receiving the entry (remote_body). From a store server that sends a Server-Timing header, as qk’s does, remote_response adds it as server: the part of the wait the server spent, the rest being the network. The last adds bytes, what was received, held_bytes, how much of the files it carried the local cache held already, apart_bytes, what was received for outputs stored apart, and skipped_bytes, the outputs stored apart that were not fetched because the local cache held them. Fetching outputs stored apart is remote_blobs, with their count, and waiting for another fetch of the same entry is remote_flight_wait. Fetches made ahead of the tasks that need them are timed under the task prefetch, and a run that prefetched ends with task=run stage=remote_prefetch, counting the entries fetched ahead, those claimed by a task, and the bytes received. Runtime lines identify the command; other lines identify the task. Spans can overlap: runtime evaluation and the inventory are part of input resolution, restore phases are part of local restoration, and storing new warm files is part of saving warm state. Do not sum them as exclusive costs. Shared runtime commands are timed only when evaluated, so a task reusing a result has no separate runtime line.

The flag leaves task stdout and cache results unchanged. Timings are diagnostic stderr output, available with every output style, and are not task warnings. Compare repeated runs with the same cache state; a remote fetch, a local restore into missing outputs and a hit with outputs already present do different work.

Change selection

affected, show affected, show tasks, and show projects accept:

OptionBehavior
--base <revision>Base: NX_BASE, then defaultBase, then main
--head <revision>Head: NX_HEAD, otherwise working tree
--affected-profile <name>Opt-in refinement of selection from qk:affectedProfiles: change projections, which apply to project selection and require a committed comparison, and import reachability, which applies to project and task selection and requires the head to be the checkout
--fail-on-projection-fallback[=all|adapter]Fail on every fallback (bare flag or all), or adapter failures (adapter) with notices for conservative comparisons; requires --affected-profile and a committed head, rejects explicit/working-tree file selection
--files <paths>Replace Git comparison with named workspace-relative paths
--stdinRead changed workspace-relative paths from stdin, one per line; an empty list means no changes
--uncommittedOnly uncommitted changes
--untrackedOnly untracked files

show projects change options imply --affected. As in Nx, --head needs --base; --files, --stdin, --uncommitted and --untracked exclude --base, --head and each other, except that the paths --stdin reads are added to --files. --stdin preserves spaces in paths. For show tasks, use --affected to filter the planned tasks. affected --granularity task selects tasks by their inputs and --granularity project the targets of affected projects; without it, NX_LEGACY_AFFECTED, then nx.json affected.legacy, decide, and tasks are the default, as in Nx 24. See Tasks or projects. See Affected selection for merge-base behavior.

Selection and inspection

run-many, affected and show tasks accept -t/--targets (--target too), -p/--projects and --exclude; lists accept commas, spaces or repeated flags. run-many accepts Nx’s deprecated --all, the default; --all=false without --projects selects nothing, as in Nx. show projects accepts -p/--projects, --exclude, -t/--with-target, --type app|lib|e2e, and --sep. --sep conflicts with --json. With --affected and -t, it lists the projects owning an affected task of the targets under task selection, which --granularity decides as for affected, except that, as in Nx, -p selects projects unless given --granularity task. --affected-targets lists the projects where a task of one of the targets is affected by its inputs, narrowed by --affected-profile, whatever the granularity; it has no Nx equivalent. Quote name/tag globs so the shell does not expand them.

show runs --limit defaults to 20, and show task <id> --limit to 10. show run without an ID uses the most recent run. All support --json. show flaky [task] --limit defaults to 20 task/key groups and supports --json. show log <run> <task> replays output to its original stdout/stderr streams. See Run history for retention limits and interpretation.

Cache administration

cache path prints the location without creating it. cache prune uses --max-size, else NX_MAX_CACHE_SIZE, else maxCacheSize, else the default disk fraction. See Storage limits.

reset, or its alias clear-cache, removes the local cache and this worktree’s state: file digests, output records and warm directories. The cache is shared by the repository’s worktrees, so resetting clears it for all of them. Run history and the remote cache are kept. --only-cache and --only-workspace-data (or --onlyCache and --onlyWorkspaceData) limit it to one of the two; --only-daemon and --only-cloud are accepted without effect.

Accepted Nx options

--runner, --batch, --skip-sync, --cloud, --no-cloud, --dte, --no-dte, --agents, --tui, --no-tui, and --tui-auto-exit, and --verbose on show projects, are accepted without effect. They do not enable Nx plugins, distributed execution or Nx Cloud. As in Nx, --runner must name default or a runner in nx.json tasksRunnerOptions.

Target inspection

qk show target <project:target[:configuration]> --json shows the resolved executor, options, caching and concurrency settings, task dependencies, readyWhen with the timeout its check gets, or null where it turns one off, and qk’s own fields, such as qk:warm and qk:threads, as configured. -c <configuration> selects a configuration. A target name without a project uses the current project, as run does.

qk show target inputs <target> --json lists files and declared environment, runtime and dependency-output inputs. qk show target outputs <target> --json lists resolved output patterns, existing output paths and unresolved templates. Without --json, inputs and outputs print one entry per line. Inspection does not load dotenv files, execute runtime inputs or require a supported executor. The listed inputs include qk’s mandatory workspace and package configuration files; these can differ from Nx’s hash plan.

Both input and output commands accept --check <values...>. File and directory queries use workspace-relative paths. Inputs also accept declared environment variable names and runtime commands. The command exits with 1 if any query does not match. --json returns each query and its membership result.

Key inspection

qk show hash <project:target[:configuration]> prints the key qk run would cache the task under now, without running the task, and a summary of what the key covers: the declared inputs, file count, env and runtime values, dependencies and tooling. --json prints the key and everything it is computed from, with set env values shown as "<redacted>" and unset ones as null. Arguments after -- are forwarded as qk run forwards them, to both tasks with --against <task>. A target name without a project uses the current project.

Computing a key executes the task’s runtime inputs. Dependencies are not run: each counts as having succeeded, with its outputs as they are on disk, so a dependency that has not run yet, or whose outputs are stale, keys differently here than after it runs.

--against <task> keys another task the same way, a target name alone naming one of the current project’s targets, and lists where the two keys differ: the definition fields with both values, the files added, removed or changed, and the values and dependencies that differ. --against <run-id> compares with this task’s key in a recorded run, as qk show runs lists them, while that run’s inputs are kept. Differences read from the --against key to this one. Two different tasks always differ in id. With --json, the report holds both keys and their inputs, same, and differences in the shape qk show task reports causes.

$ qk show hash web:build --against web:check
web:build  55a02f0c…
web:check  963b6121…
keys differ in: definition, files
  field id: "web:check" -> "web:build"
  field definition.inputs[0]: "{projectRoot}/src/**/*" -> "{projectRoot}/**/*"
  field definition.inputs[1]: {"runtime":"node -v"} -> {"env":"MODE"}
  field definition.inputs[2]: {"env":"MODE"} -> {"runtime":"node -v"}
  added apps/web/README.md

The target definition is part of the key as written, so reordering inputs changes the key even when the files and values it selects do not; such a change shows as definition.inputs reordered.

Project watch

qk watch -p web --includeDependencies -- <shell command> watches the selected projects and, optionally, their project dependencies. --all watches all projects, including projects created after watch starts. --initialRun runs once before waiting for edits. -g/--includeGlobalWorkspaceFiles also reacts to files that belong to no project, such as root configuration; as in Nx, a command naming NX_PROJECT_NAME is refused with it. The kebab-case aliases also work.

Callbacks run from the invocation directory with NX_PROJECT_NAME and NX_FILE_CHANGES (workspace-relative paths joined with spaces). If the command mentions NX_PROJECT_NAME, a batch runs concurrently once per changed project; otherwise it runs once for the batch with an empty project name. Initial --all also runs once with an empty project name, matching Nx. Quote the shell command so variables expand in the callback rather than in the invoking shell.

Native file events are debounced and changes arriving during a callback are queued for the next batch. A directory event or backend rescan can include other eligible source files in the reported batch. Callback failures are reported; watch continues. Edits to sources known to be regular files reuse the current project view. Configuration and ignore-policy changes, file creation/deletion, directories, symlinks and backend rescans reload discovery and selection before the next callback. Workspaces using package presets or presets outside the workspace retain a reload on every source batch, because preset resolution has inputs outside the source set. Ctrl+C cancels callbacks and their process groups and exits with 130. Ignored source files, node_modules, Git/qk state, configured caches, explicit target outputs and warm paths do not trigger callbacks. Files outside any selected project do not trigger callbacks, unless -g is given and they belong to no project at all. Watch uses no daemon or Nx plugins.

Compatibility diagnostics

qk doctor reports unsupported executors, configured Nx plugins, sync generators and fields in qk:warm or qk:threads that this qk does not know, without executing commands, loading dotenv files or running plugins. It also reports dependentTasksOutputFiles globs that select nothing for any task of a target, which therefore key nothing: none of those tasks depends on a task declaring outputs, or the outputs on disk hold no file the glob matches. Outputs not built yet are taken to match. Targets sharing a set of such globs, as through a named input, are one finding. It also lists Nx CLI options accepted without effect. --json returns a versioned report with stable finding codes, locations and error/warning counts. Unsupported executors cause exit code 1; --strict also fails on warnings.

This checks normalized explicit target definitions. A clean report does not establish that commands can execute or that plugin-inferred targets exist.