The table column style rule added since 0.35.0 is disabled, since the docs pad tables loosely rather than aligning every pipe, and the docs are updated for the other rules it now enforces.
8.5 KiB
Build Tracking
Important
New as of 0.38.0
Every deploy that flows through Dokku - whether triggered by git push, ps:rebuild, ps:restart, config:set, or git:from-archive / git:from-image / git:sync / git:load-image - is recorded as a structured build record on disk. The builds plugin lets operators inspect what is currently deploying, look up the result of an old deploy, and stream the captured build log without depending on journalctl.
builds:cancel <app> # Cancel a running build for an app
builds:info <app> <build-id> [--format json] # Show details for a single build
builds:list [<app>] [--format json] [--kind ...] [--status ...]
# List builds (running across all apps, or running + history for one)
builds:output <app> [<build-id>|current] # Show build output (tail for live, cat for finished)
builds:prune <app> [--all-apps] # Reap abandoned records and apply retention
builds:report [<app>] [<flag>] # Display a build report
builds:set [--global|<app>] <key> [<value>] # Set or clear a builds property
Build records
Every build is identified by a sortable base36 ULID-style id (DOKKU_BUILD_ID) generated at deploy start. For each build, Dokku writes:
$DOKKU_LIB_ROOT/data/builds/<app>/<build-id>.json- the structured record$DOKKU_LIB_ROOT/data/builds/<app>/<build-id>.log- the captured stdout/stderr of the deploy
Output is also tagged into syslog as dokku-<build-id> so journalctl -t dokku-<build-id> continues to work. The on-disk log file is the durable source of truth and is read for builds:output even when journald has rotated old entries away.
A deploy that exits early - for example when the build fails - still finalizes its record as failed with its exit code.
A run that builds nothing leaves no record behind. This includes a deploy refused because the app was locked via apps:lock. git:sync has to fetch before it can tell whether there is anything to deploy, so it opens a record up front and discards it again when it turns out there is not - a git:sync with no --build flag, or a --build-if-changes poll that finds the remote unchanged. Without that, an app polled on a timer would accumulate running records that are later reaped as spurious failures, pushing real deploys out of the retention window.
Record schema
{
"id": "01j8c4xv7bk5w3",
"app": "myapp",
"kind": "build",
"pid": 12345,
"started_at": "2026-04-30T13:50:00Z",
"finished_at": "2026-04-30T13:51:14Z",
"status": "succeeded",
"source": "git-hook",
"exit_code": 0
}
- kind -
buildfor paths that produce a new image (git push,git:*,ps:rebuild);deployfor paths that re-deploy an existing image (ps:restart,ps:start,dokku deploy,config:set). - status - on-disk values are
running | succeeded | failed | canceled.abandonedis a fifth display-only value computed at read time forrunningrecords whose PID is no longer alive; it is never persisted to the record. - source - the user-typed command that originated the deploy (e.g.
git-hook,ps:restart,config-redeploy,git:sync).
Listing builds
Without an app argument, builds:list shows currently-running builds across every app on the host:
dokku builds:list
=====> Currently running builds
App Build ID Kind PID Source Started
myapp 01j8c4xv7bk5w3 build 12345 git-hook 2026-04-30T13:50:00Z
With an app, builds:list returns running builds plus the most recent finalized records up to the configured retention:
dokku builds:list myapp
Filter by kind or status:
dokku builds:list myapp --kind build
dokku builds:list myapp --status running
dokku builds:list --format json
Inspecting a single build
dokku builds:info myapp 01j8c4xv7bk5w3
=====> Build 01j8c4xv7bk5w3
Build ID: 01j8c4xv7bk5w3
App: myapp
Kind: build
Status: succeeded
PID: 12345
Source: git-hook
Started: 2026-04-30T13:50:00Z
Finished: 2026-04-30T13:51:14Z
Duration: 1m14s
Exit Code: 0
Log: /var/lib/dokku/data/builds/myapp/01j8c4xv7bk5w3.log
JSON output includes the same fields plus a computed log_path:
dokku builds:info myapp 01j8c4xv7bk5w3 --format json | jq .
Streaming build output
# tail -f the live build, or cat the log for a finished one
dokku builds:output myapp 01j8c4xv7bk5w3
# resolve "current" from the in-flight deploy
dokku builds:output myapp current
If the on-disk log file is missing (for example, a build from before this plugin was installed), builds:output falls back to journalctl -t dokku-<build-id>.
Cancelling a build
builds:cancel reads the active .deploy.lock for an app, looks up the matching build record, and sends SIGQUIT to the deploy's process group. The record is finalized as canceled (or failed if the process had already exited without finalizing - in that case Dokku marks the record so it doesn't sit in running forever).
dokku builds:cancel myapp
If the record is already finalized when cancel runs, no signal is sent and the record is left untouched.
Retention
Build records are pruned by count, not by age. The default retention is 20 records per app. Live in-flight deploys are never pruned regardless of count.
Set a per-app retention:
dokku builds:set myapp retention 50
Set the global default:
dokku builds:set --global retention 10
Clear an override (falls back to the global value, then the default):
dokku builds:set myapp retention
Manual pruning
builds:prune invokes the same logic that runs at the end of every deploy - it reaps abandoned records (status=running with a dead PID, finalized as failed) and trims the directory to the configured retention. Useful after lowering retention via builds:set or to clean up after a host reboot:
dokku builds:prune myapp
dokku builds:prune --all-apps
Reports
dokku builds:report
dokku builds:report myapp
dokku builds:report myapp --build-status
Available flags:
--build-id,--build-kind,--build-status,--build-pid,--build-source,--build-started-at,--build-finished-at,--build-exit-code: details of the most recent build for the app--builds-retention: per-app retention override (empty if none)--builds-global-retention: global retention override (empty if none)--builds-computed-retention: the resolved retention applied to this app
--build-status returns the display status, so an abandoned in-flight build shows abandoned rather than running. The raw on-disk status is only visible by reading the JSON record directly.
Properties
Settable properties
Note
The
Report flagscolumn lists the CLI argument names accepted bybuilds:report. The JSON keys emitted bybuilds:report --format jsonare the same names with the leading--builds-stripped (e.g.retention,global-retention,computed-retention). Legacy keys with thebuilds-prefix (e.g.builds-retention) are also emitted during the 0.38.x deprecation window and will be removed in a future major release. Status keys (build-id,build-status, etc.) have no plugin prefix and are unaffected.
| Property | Scope | Default | Report flags | Description |
|---|---|---|---|---|
retention |
app + global | 20 |
--builds-retention, --builds-global-retention, --builds-computed-retention |
Number of recent build records kept per app; older finalized records are pruned at the end of each deploy |
Read-only flags
The following flags surface in builds:report but are not managed by builds:set - they are derived metadata recorded during the build:
| Flag | Description |
|---|---|
--build-id |
Unique identifier of the most recent build for the app |
--build-kind |
Whether the record was a build or a deploy |
--build-status |
Display status (running, succeeded, failed, canceled, abandoned); computed at read time |
--build-source |
Trigger that started the build (e.g. git-hook, ps:rebuild, ps:restart) |
--build-pid |
PID of the build process |
--build-started-at |
UNIX timestamp the build started |
--build-finished-at |
UNIX timestamp the build finished |
--build-exit-code |
Exit code of the build process |