Appearance
nkapp containers prune
Remove stopped, aged-out, unclaimed containers. This is the container analogue of nkapp volumes prune and nkapp images prune, and the three share one selection authority with the Hub, so the CLI and the dashboard can never disagree about what is prunable.
bash
nkapp containers prune [options]A side-effect-free preview is always rendered first — a table of the containers that would be pruned plus a skipped count — before anything is removed. --dry-run stops there.
What gets pruned
A container is pruned only when all of these hold:
| Guard | Rule |
|---|---|
| State | exited or created. A running, paused or restarting container is never touched, and no flag changes that. |
| Age | It stopped at least --older-than ago (default 24h). An exited container is aged on its exit time, never its creation time, so a service that ran for days and exited a second ago is never swept. If the exit time cannot be determined, the container is skipped. |
| Ownership | It is labeled for this project + environment, or is an unlabeled legacy container named nk-<project>-<env>-…. A container labeled (or named) for another project or environment is never removed. |
| Not declared | It is not a service, database or system container declared in nanokit.yml. A service you deliberately stopped may be exited and months old; it is never garbage. |
Options
| Flag | Type | Default | Description |
|---|---|---|---|
-e, --env <env> | string | local | Environment to use |
--ssh <host> | string | — | Target an explicit host (e.g. root@1.2.3.4), overriding the environment's configured deploy target — prunes stranded / cross-host stale containers |
-p, --port <port> | number | 22 | SSH port (used with --ssh) |
-i, --ssh-key <path> | string | — | SSH private key override (used with --ssh) |
--older-than <dur> | string | 24h | Minimum time since the container stopped — 30s, 15m, 24h, 7d, or 0 to disable the age gate |
--unlabeled | boolean | false | Also prune containers carrying no Nanokit labels at all |
--dry-run | boolean | false | List what would be pruned, change nothing |
-y, --yes | boolean | false | Skip the confirmation prompt |
An unparseable --older-than value fails the command before any connection is opened, rather than being guessed at.
Why --unlabeled exists
Nanokit's cron scheduler creates a fresh container per job fire, and it exposes no option to label them — so those containers are auto-named (suspicious_jackson, …) and carry no Nanokit labels. When the scheduler's own reap fails, the stray is invisible to every label-scoped Nanokit command and accumulates forever. Left unchecked this class of leak has reached thousands of container directories and taken down a Docker daemon.
--unlabeled is opt-in because it is the one mode that reaches containers Nanokit did not demonstrably create. Always inspect the --dry-run table first.
Not wired into reconcile
up and deploy do not run this prune. Removing containers mid-deploy is a surprise you did not ask for, and the sweep that actually catches the cron strays requires --unlabeled, which is far too broad to run implicitly. Detection is automatic (nkapp doctor → Container Hygiene); removal stays an explicit, reviewable command.
Examples
bash
# Review what would be removed locally
nkapp containers prune --dry-run
# Prune stale containers on the staging host
nkapp containers prune -e stage -y
# Include the unlabeled cron strays — inspect first
nkapp containers prune --unlabeled --dry-run
nkapp containers prune --unlabeled -y
# Target a stranded host directly
nkapp containers prune --ssh root@1.2.3.4 -i ~/.ssh/id_rsa --dry-run
# Sweep anything that stopped more than an hour ago
nkapp containers prune --older-than 1hExecution is best-effort: per-container failures are aggregated and reported, and any failure exits non-zero.