Command Reference
Every dx command runs through Bazel. Put dx flags after the command,
Bazel flags after --. @rules_dx//:dx is the public launcher; inside this
checkout //:dx is the same target.
Locally, Bazel reads ~/.bazelrc and the system rc for every dx call. Under
CI=true and inside Bazel tests, dx passes --nohome_rc --nosystem_rc.
bazel run @rules_dx//:dx -- build //...
bazel run @rules_dx//:dx -- lint --check //... -- --jobs=4
dx build,dx test,dx coverage,dx run,dx deploydx lint,dx typecheck,dx formatdx check,dx fix,dx cleandx generatedx env,dx codegendx security,dx license,dx update,dx bump,dx adddx docsdx initdx status,dx versiondx list-testsdx completiondx migratedx new,dx upgrade,dx rollbackdx watchdx worktree
Scope rules live in Scope Defaults.
Airgapped hosts install from a vendored bundle: see Offline Bundle.
A .dx/version pin that disagrees with the rules_dx version dx was built
from stops most commands. See Version Skew.
Build Slots
dx build, test, coverage, deploy, lint, typecheck,
format, check, fix, generate, codegen, env, security, license,
docs and list-tests take a build slot before they call Bazel.
dx run holds a slot only while it builds and frees it before the app starts.
dx watch takes one slot per iteration and holds none while it waits for
changes. dx update takes one slot at its first updater that runs Bazel and
holds it until its updaters finish. dx update --check and updaters that do
not run Bazel take none. Slots are shared by every
worktree and every user session on the machine. The slot count is the machine
memory, or the cgroup memory limit if lower, divided by 3 GiB. There is always
at least one and never more than 16. The count has no setting.
When the Bazel config sets a non-empty --remote_executor, dx offers more
slots: the memory divided by 1.5 GiB, at most 16. dx reads this from the rc
files Bazel reads, their --config sections, and the flags you pass. A run
takes an extra slot only when no regular slot is free, the host is not under
memory pressure, and no other run took an extra slot in the last 10 seconds.
On Linux, memory pressure means /proc/pressure/memory some avg10 is 10 or
more, or MemAvailable is below 1.5 GiB when that file is missing. macOS and
Windows get no extra slots. A run that waits only because of memory pressure
says so in its waiting notice.
While a slot is held, dx adds two flags right after build, test,
coverage and run:
--local_resources=cpu=<n> --local_resources=memory=<mb>
n is the CPU count divided by the slots held right now, extra slots and
this one included, and never less than 2. mb is the memory, less the memory kept for nested
Bazel test servers, divided by the same number, in MiB. The values are fixed
when dx takes the slot. Nested dx calls reuse them through DX_BUILD_SHARE.
dx adds neither flag when an rc file Bazel reads sets that resource to a value
other than the vendored preset default. It also skips a resource you pass after
--:
dx build //... -- --local_resources=cpu=4
CI runs and dx runs inside a Bazel test add neither flag.
When all slots are taken, or other runs already wait, dx waits and prints one line to stderr:
dx: waiting for a build slot (held by /path/to/worktree and 5 more, 2 ahead in line)
The line names one current holder, how many other slots are held, and how many
runs wait ahead. Waiting runs get a slot in the order they started waiting. A
waiter that exits or is stopped leaves the line. A waiter suspended for over 30
seconds does not hold up the line until it resumes. If dx cannot use the
queue directory next to the slot files, it waits without a line.
With --output=json, dx also writes one notice event with code
waiting_for_build_slot right after command_started. The slot frees when the
Bazel work ends or dx exits, including when it crashes.
While dx waits, it keeps the worktree's running Bazel server from shutting down for idleness. It never starts a server.
If dx cannot write a slot file, it locks it read-only. If it still cannot use
a slot file, it prints dx: skipped build slot <path>: <error> once and runs
with one slot fewer. With --output=json it also writes one warning notice
event with code build_slot_skipped.
If dx can use no slot file, it prints dx: build slots disabled: <error> and
runs without a slot. With
--output=json it also writes one notice event with code
build_slots_disabled.
Ctrl-C or SIGTERM during the wait stops dx at once. dx prints
dx: cancelled: stopped by signal N and exits 128 plus the signal number.
status, version, worktree, completion and the other commands that do not
run Bazel never take a slot. A dx call started while DX_BUILD_SLOT is set, or
from inside a Bazel test, takes no second slot. While dx holds a slot, the
Bazel and tool processes it starts see DX_BUILD_SLOT=1 and DX_BUILD_SHARE
set to cpu=<n>,memory=<mb>. dx run apps start
after the slot frees.
Disk Space
Before each Bazel build it starts, dx checks free space on the workspace disk, the Bazel output base, the temp dir and the home dir. When one has under 1 GiB free, dx prints one line to stderr and keeps going:
dx: disk_low: 512.0 MiB free at /path; free disk space with `dx worktree prune --apply`
With --output=json, dx also writes one notice event with code disk_low
and level warning.
dx run and dx deploy check before the build, not before the app starts, and
an app's exit code is never reported as disk_full.
When the disk holding the worktree pool has under 20 GiB and under 10% free,
or under 1 GiB free,
dx drops orphaned output bases, repository cache downloads unused for 30 days,
and free slots' output bases each time it
takes a build slot: once for each command above, for each watch iteration,
for the build run does before the app starts, and for update when it runs
Bazel. This also happens when build slots are disabled. It never drops the
output base of the workspace being built. dx prints one of these lines to
stderr only when it removed something or could not reclaim:
dx: low disk: <free> free; removed <what>; <free> free now
dx: low disk, cannot reclaim output bases: <error>
With --output=json, dx also writes one notice event with code disk_low
and level warning, after command_started and before that build's output.
dx worktree add and dx worktree hook create also refuse with code
disk_full when the pool's disk has under 1 GiB free after that reclaim.
Inspecting The Graph
dx has no owners, deps, or why command. Use native Bazel. Quote every
expression.
bazel query 'rdeps(//..., //pkg:target, 1)'
bazel query 'deps(//pkg:target)'
bazel query 'somepath(//app:server, //lib:core)'
bazel cquery 'deps(//pkg:target)' --platforms=//platforms:linux_x86_64
bazel query 'kind(rule, rdeps(//..., @repo//pkg:target, 1))'
query reads the unconfigured graph. cquery reads the graph for the
selected platform and flags. An empty result is not a pass: check the exit
code.
Global Flags
Every command takes these:
--help(-h): print help.--version(-V): print the dx version.--workspace <dir>: run in another workspace. A relative dir starts from the current directory.--quiet[=bool](-q),--verbose[=bool](-v): less or more output. Bare meanstrue, and=falseturns off a default inherited from the environment or a config file. Short flags cluster (-qv); repeating-vchanges nothing.--color auto|always|never: color output. Defaultauto.--bazel-startup-option <token>: Bazel startup option, repeatable. Takes--output_base=<path>or--output_user_root=<path>. Inserted before the Bazel verb for every managed invocation. Isolated output bases isolate concurrent runs.
Every other flag belongs to one command family. dx <command> --help lists
only the flags that command takes, and a flag from another family is a usage
error.
Read commands take --output text|json (-o). -o json, -ojson and short
clusters such as -qojson all work. Commands that can print a patch also take diff. Commands that only
print text take no --output.
Check commands take --fail-on info|warning|error (default warning) and
--report <format>=<dest>. Repeat --report for more files. A relative
<dest> anchors at the workspace root wherever dx runs; an absolute <dest>
writes outside the workspace as given. Two flags resolving to the same file fail
before anything runs, including ./ and parent/../ spellings of one path.
Parent directories must already exist. A failed write names the resolved file and
the cause, exits nonzero, and keeps the previous file bytes. Each command page
lists its report formats. Coverage also takes --min-coverage <percent> and
fails below it.
Network commands take --offline and --frozen. --offline means no network:
use pinned cached snapshots or fail. --frozen means no manifest or lock
resolution changes and may fetch already pinned content. Combine them for both
policies. Older dx versions spelled offline as --frozen: pass --offline for
that behavior.
--check, --apply, --debug, --release, --here, and --affected are
documented on the command pages that take them. --here limits a command to the
current directory tree. --affected limits it to targets your changes reach. --apply never combines with --check. Bare --debug or
--release means dev, except for deploy, where it means release.
Exit codes: 0 success, 2 usage error, 1 failed check.
A usage error names the offending token, prints a tip: a similar ... line when
a near match exists, then prints the usage line above. With no command, the usage
error prints the command list and a see dx <command> --help hint.
JSON Output
--output=json writes one JSON object per line to stdout. Every object has an
event name and a schema with major and minor. The schema is 3.0.
Readers accept any 3.x and reject other majors. The stream starts with one
command_started and ends with one command_finished. Diagnostics and logs go to
stderr. A failure before the command starts emits error and then
command_finished with no command_started; that command_finished carries
the process exit code and results_complete: false. If dx cannot build an
event, it writes error with code invalid_result, then command_finished,
and exits 1. DX_OUTPUT=json and
output = "json" in dx.toml give the same stream, also when the rest of
dx.toml is invalid. A stop signal ends the run with no error and no
command_finished; dx exits 128 plus the signal number. A closed stdout
exits 141.
bazel run @rules_dx//:dx -- lint --check //... --output=json
Agent sessions
When CLAUDECODE, CODEX_THREAD_ID, CURSOR_AGENT, GEMINI_CLI, or
AI_AGENT is set, the default output is json for commands that support it,
and Bazel progress stays off stderr. --output and DX_OUTPUT still win, and
so does output in dx.toml. In CI these variables are ignored.
Empty optional fields are left out of test_outcome and build_failure events. A plain
pass is not an event. dx test and dx coverage count passed, failed, cached, no_cases, and skipped tests
in command_finished and write every test to the results report. Each count is
per result, so a target with four shards counts four. Equal
build_failure and diagnostic events from different targets and
configurations appear once, with a count.
command_started: the command and its mode.build_failure: one failure Bazel reported while building, fromdx build,dx test, anddx coverage. It hasrecord_version,target,configuration,target_kind,stage,category,action,tool,message, anddiagnostics, whose items may carry arelatedlist. Facts Bazel did not report readunknown. The same failure from several targets or configurations is one event with acountand up to 20 othertargets.capability: one declared capability, withname,source,availability,detail,flags,outputs,reports,scope_policy,effect, andpassthrough.operation: a phase, with the scopes it resolved to.selection: the resolved environment, assetup_id,environment_id, andcodegen_iddigests.status: one check, withname,status,detail, andhint.slot: one worktree slot, withaction,path,state, andserver, plus optionalslot,branch,holder,reason,base, anddisk_bytes.reasonsays why a slot or worktree was kept.summary: the pool totals fromdx worktree list, withslots,servers, andservers_rss_bytes, plus optionaldisk_bytesanddisk_cache_bytes.diagnostic: one finding, withseverity,tool,message,location,snapshot,fixable, andcount, plus optionalrule,path,range,package,resolution,baseline,origins, andrelated.locationisunknown,file,bytes, orlines. Arangewithlineslocation addsstart_line,start_column,end_line, andend_column, all 1-based.countis how many identical findings this one stands for.baselineissuppressedwhen the baseline holds the finding. Each oforiginsnames theproducer,target, andconfigurationthat reported it.packagenames the dependency of avulnorlicensefinding, withnameandversion, plusfixedfor a vulnerability andlicensefor a license finding. An emptyfixedlist means no fixed version exists.change: one file edit, withpath,kind,edit_count, andeffect.effectisproposedin check mode, andappliedorrefusedwith--apply. Arefusedchange carries areason.--include-editsaddssource_digestand the fulledits.phase_started: adx checkordx fixphase began, withcommand,phase,mode, andcorrelation. Every event of the phase carries the samecommand,phase, andcorrelation.phase_finished: a phase ended, with itsexit_codeand counts.notice: a note, withlevel,code,message, and optionalrelated_command,scope,path,language, andimport.report: a report written, withformat,path, andresults_complete.formatisjunit,lcov,failures, orresults.test_outcome: one test result except a plain pass, withtargetandoutcome, plus optionalconfiguration,status,cached,run,shard,attempt,final,duration_millis,cases_total,cases_failed,cases_error,cases_skipped,cases_omitted,artifacts, andevidence_complete.evidence_completeandartifactsappear only when evidence is missing.finalisfalseonly on an attempt that a later attempt replaced. A failing result addsfailing_cases(up to 10, each withclassname,name,outcome, and amessagecut to 1024 bytes),failing_cases_omitted,log_path, andlog_tail(the last 40 lines, at most 8 KiB of the test log).error: a failure, withcode,message, and optionalcause,status,excerpt,truncated,path,flag, andphase.causeis one ofinput,defaults,query_launch,query,analysis,bazel,test,application,tool_unavailable,collection,report,host,operational, orunknown.bazel_failedhas causebazel;tests_failedhas causetest;application_failedis adx runapplication that exited nonzero and has causeapplication.disk_fullhas causehost: a Bazel run or query exited 36 and a disk it writes to has under 1 GiB free. dx keeps exit 36 and prints anext:line suggestingdx worktree prune --apply.statusis the exit code of the failed Bazel run or application.excerptholds the last lines Bazel printed to stderr, andtruncatedistruewhen lines were cut.command_finished: theexit_code, plus anyresults_complete,run_id,diagnostics,tests, andchangescounts.testshaspassed,failed,cached,no_cases, andskipped. Each counts results (per target, configuration, run and shard), so a target with four shards counts four.failedcounts results whose final attempt has outcomefailedortimeout; earlier failed attempts of a retried test still appear astest_outcomeevents withfinal: falseand are not counted.cachedcounts the passed tests that came from the cache.no_casescounts passed tests whose report had no test cases; they are also inpassed.skippedcounts tests with outcomeskippedorfiltered.changeshascreateandmodify, and with--applyalsoappliedandrefused.
dx run and dx update add correlation to their events, so you can group
them by target or set.
Environment
Every variable below supplies a default. A flag on the command line wins, and
--quiet=false, and --verbose=false turn an inherited
default off.
DX_WORKSPACE=<dir>: default for--workspace.DX_QUIET=<bool>: default for--quiet.DX_VERBOSE=<bool>: default for--verbose.DX_COLOR=<mode>: default for--color.DX_OUTPUT=<mode>: default for--output.DX_FAIL_ON=<level>: default for--fail-on.NO_COLOR=<any>: disables color inautomode, even when empty.--color alwaysstill colors.BUILD_WORKSPACE_DIRECTORY=<dir>: workspace start underbazel run.BUILD_WORKING_DIRECTORY=<dir>: current directory underbazel run.
A <bool> is on for true and off for false, case-insensitive and trimmed.
Any other non-empty value is a usage error. An empty value is unset.
A DX_OUTPUT or DX_FAIL_ON value that a command does not support is ignored
for that command, as in the config file.
Config File
dx.toml (committed) and dx.local.toml (local-only, gitignored) set the
same defaults. A key
is the flag name without --.
[dx]
workspace = "/path/to/repo"
quiet = true
verbose = true
color = "never"
output = "json"
fail-on = "error"
Values are TOML, so a boolean key takes true or false. An empty value is
unset. Defaults live only under [dx] with the hyphenated flag names. A
top-level default or fail_on is a usage error.
An unknown key is a usage error that names the key and the keys it accepts.
Other supported sections in the same file stay valid.
Unsupported defaults are ignored per command. An output default that a
command does not support falls back to the command's default output: json in
an agent session for commands with JSON output, else text. For example, with
output = "diff" an agent session runs dx test with json. An unsupported
fail-on default falls back to warning. The same value as a flag is a usage
error. An invalid value is always a usage error.
Commit shared
defaults in dx.toml and keep personal overrides in dx.local.toml. Local
beats committed. No other file is read for defaults.
The nearest file to the working directory wins, and its values sit below the environment. The search
reads the working directory and each directory above it, so a neighboring or
nested workspace tree never supplies defaults. Under bazel run the search
starts at the workspace root. In CI the local file and DX_ variables are
ignored. Flags still win. CI never implies --apply.
The command line wins over the environment, and the environment wins over
the file. Defaults load from the selected workspace: --workspace or
DX_WORKSPACE selects it before the file is read. A workspace key in the
file redirects once to that workspace. A relative workspace key starts
from the workspace start. -h, --help, help, -V, and
--version print without reading a broken config. dx new and
dx completion run outside a workspace. Deleting .dx keeps committed
behavior. Read-only commands never rewrite config.
Supported Surface
@rules_dx//:dx runs every command.
Language rules:
@rules_dx//android/rules:defs.bzl: Android libraries.@rules_dx//apple/ios:app.bzl: iOS apps, tests and frameworks.@rules_dx//apple/ios:defs.bzl: iOS libraries.@rules_dx//cc/rules:defs.bzl: C and C++.@rules_dx//csharp/rules:defs.bzl: C#.@rules_dx//cuda/rules:defs.bzl: CUDA.@rules_dx//cue/rules:defs.bzl: CUE.@rules_dx//elixir/rules:defs.bzl: Elixir.@rules_dx//erlang/rules:defs.bzl: Erlang.@rules_dx//fsharp/rules:defs.bzl: F#.@rules_dx//gherkin/rules:defs.bzl: Gherkin.@rules_dx//gleam/rules:defs.bzl: Gleam.@rules_dx//go/rules:defs.bzl: Go.@rules_dx//html_template/rules:defs.bzl: HTML templates.@rules_dx//java/rules:defs.bzl: Java.@rules_dx//javascript/rules:defs.bzl: JavaScript.@rules_dx//javascript/rules:web.bzl: web apps and dev servers.@rules_dx//jsonnet/rules:defs.bzl: Jsonnet.@rules_dx//kotlin/rules:defs.bzl: Kotlin.@rules_dx//lua/rules:defs.bzl: Lua.@rules_dx//perl/rules:defs.bzl: Perl.@rules_dx//pkl/rules:defs.bzl: Pkl.@rules_dx//powershell/rules:defs.bzl: PowerShell.@rules_dx//python/rules:defs.bzl: Python.@rules_dx//qt/rules:defs.bzl: Qt.@rules_dx//qt/rules:rust.bzl: Rust libraries for Qt.@rules_dx//ruby/rules:defs.bzl: Ruby.@rules_dx//rust/rules:defs.bzl: Rust.@rules_dx//scala/rules:defs.bzl: Scala.@rules_dx//sql/rules:defs.bzl: SQL.@rules_dx//terraform/rules:defs.bzl: Terraform.@rules_dx//typescript/rules:defs.bzl: TypeScript.@rules_dx//vue/rules:defs.bzl: Vue.@rules_dx//xml/rules:defs.bzl: XML.@rules_dx//yaml/rules:defs.bzl: YAML.@rules_dx//zig/rules:defs.bzl: Zig.
Packaging and deploy:
@rules_dx//android/packaging:defs.bzl: APKs, App Bundles and adb.@rules_dx//appimage:defs.bzl: AppImage bundles.@rules_dx//apple/ios:device.bzl: signed iOS IPA export.@rules_dx//apple/provisioning:defs.bzl: Apple provisioning.@rules_dx//apple/provisioning:probe.bzl: Apple toolchain probe.@rules_dx//deploy/offline:offline.bzl: offline bundles.@rules_dx//deploy/rules:archive.bzl: release archives.@rules_dx//deploy/rules:cloudflare.bzl: Cloudflare deploys.@rules_dx//deploy/rules:crates.bzl: crates.io publish.@rules_dx//deploy/rules:github.bzl: GitHub releases.@rules_dx//deploy/rules:maven.bzl: Maven publish.@rules_dx//deploy/rules:npm.bzl: npm publish.@rules_dx//deploy/rules:nuget.bzl: NuGet publish.@rules_dx//deploy/rules:oci.bzl: OCI images.@rules_dx//deploy/rules:octopus.bzl: Octopus Deploy.@rules_dx//deploy/rules:promotion.bzl: release promotion.@rules_dx//deploy/rules:pypi.bzl: PyPI publish.@rules_dx//msix:defs.bzl: MSIX packages.
SDK and toolchain extensions:
@rules_dx//android/sdk:repos.bzl: Android SDK.@rules_dx//android/toolchain:repos.bzl: Android NDK toolchain.@rules_dx//apple/ios:simulator.bzl: iOS simulator.@rules_dx//elixir/rules:hex.bzl: Hex packages for Elixir.@rules_dx//gleam/rules:hex.bzl: Hex packages for Gleam.@rules_dx//powershell/rules:gallery.bzl: PowerShell Gallery modules.@rules_dx//msix:repos.bzl: MSIX tools.@rules_dx//qt/sdk:repos.bzl: Qt SDK.
API docs:
@rules_dx//tools/docs/typescript:defs.bzl: TypeScript API doc shards.
Quality config:
@rules_dx//quality:native_config.bzl: native linter and formatter configs.@rules_dx//quality:policy.bzl: quality families and workspace policy.
Every other file stays private. A private file is not a dependency. Patch releases keep every supported label and flag. Minor releases add without breaking old uses. A breaking change needs a new major version and a migration. Readers tolerate added fields and fail on a new major schema. Bazel 9.2.0 is the tested baseline.
rules_dx does not provide debugger acquisition, launch or attach integration, Debug Adapter Protocol adapters, or generated debugger configurations. These are unsupported and not planned. Debug build profiles and editor language-server settings do not imply debugger support. You can set up external debuggers yourself.