This guide is for operators, platform engineers, and contributors who need to understand how lazydocker works internally, how to configure it exhaustively, how to deploy it across teams and remote hosts, and what its security posture is. For day-to-day usage and keybindings, see the User Guide.
1. Executive Summary
Lazydocker is a single-binary terminal UI for Docker and Docker Compose, written
in Go. It is a client: it holds no state of its own beyond a YAML config
file, runs no daemon or server, and exposes no network ports. It talks to the
Docker Engine through the official Docker SDK (github.com/docker/docker) and
shells out to the docker compose CLI for Compose-specific operations.
Architecturally it is the Docker sibling of lazygit (same author, same
gocui TUI foundation, same config-driven command-template philosophy). The
application is organized into three clean layers:
commands— the Docker/OS abstraction: a thin wrapper over the Docker SDK plus a shell-command runner.gui— thegocui-based terminal interface: panels, keybindings, layout, and rendering.config— user configuration with sensible defaults merged over aconfig.yml.
| Property | Value |
|---|---|
| Language | Go (go 1.22, toolchain 1.23.6) |
| TUI library | github.com/jesseduffield/gocui (a fork of jroimartin/gocui) |
| Docker access | Docker Engine SDK + docker compose CLI |
| State | Stateless; one optional config.yml |
| Network listeners | None |
| Privilege model | Inherits the caller's access to the Docker socket |
| Distribution | Single static binary (Homebrew, Scoop, Choco, AUR, Go, Docker, script) |
2. Architecture
2.1 High-level component diagram
┌──────────────────────────────────────┐
Terminal (stdin/out) │ lazydocker │
▲ │ │ │
│ ▼ │ ┌───────────────────────────────┐ │
┌──────────────┐ │ │ pkg/gui (gocui TUI) │ │
│ Keyboard / │◀────▶│ │ panels, layout, keybindings, │ │
│ Mouse / TTY │ │ │ main-panel tabs, rendering │ │
└──────────────┘ │ └───────────────┬───────────────┘ │
│ │ │
│ ┌───────────────▼───────────────┐ │
│ │ pkg/commands │ │
│ │ DockerCommand · OSCommand │ │
│ └───────┬───────────────┬───────┘ │
│ │ │ │
│ Docker SDK shell exec │
└───────────┼───────────────┼───────────┘
▼ ▼
┌────────────────┐ ┌──────────────────┐
│ Docker Engine │ │ docker compose │
│ (daemon/API) │ │ CLI subprocess │
└───────┬────────┘ └──────────────────┘
▼
unix socket / npipe / ss:// / tcp
2.2 Layer responsibilities
| Package | Responsibility | Key types |
|---|---|---|
main (main.go) |
Parse CLI flags (via integrii/flaggy), build AppConfig, construct and run the App, map known errors to friendly messages. |
— |
pkg/app |
Wire everything together: logger, translations, OSCommand, DockerCommand, Gui. |
App |
pkg/config |
Define UserConfig and all sub-configs; merge user config.yml over compiled defaults. |
AppConfig, UserConfig |
pkg/commands |
Wrap the Docker SDK (containers, images, volumes, networks, services, stats) and run shell commands. | DockerCommand, OSCommand, Container, Service, Image, Volume, Network, Project |
pkg/gui |
The entire terminal UI: side panels, main-panel tabs, keybindings, layout (boxlayout), confirmation/menu panels, filtering. |
Gui, Panels, Binding |
pkg/tasks |
Manage long-running, cancellable background tasks (log following, stat polling) so switching panels cleanly stops the previous task. | TaskManager, Task |
pkg/i18n |
Translation sets for 9 languages. | TranslationSet, Localizer |
pkg/utils |
Templating, table rendering, color helpers, byte formatting. | — |
pkg/log |
Logrus-based logging (file output when debug enabled). | — |
pkg/cheatsheet + scripts/cheatsheet |
Generate the docs/keybindings/Keybindings_*.md files from the keybinding definitions. |
— |
2.3 Startup sequence
Tracing main.go → pkg/app/app.go:
updateBuildInfo()— if built from source, derive version/commit/date from Go's embedded VCS build info.- Flag parsing (
flaggy) — read-c/-d/-f/-pand--version. If-cis set, print the default config as YAML and exit. config.NewAppConfig(...)— locate/create the config directory, loadconfig.yml, and merge it overGetDefaultConfig(). Compose files passed via-fare appended to thedockerComposetemplate as-fflags.app.NewApp(config):- Create the logger.
- Load the translation set for
gui.language. - Construct
OSCommand(shell runner). - Construct
DockerCommand: determine the Docker host, set up any SSH tunnel, create the SDK client with API-version negotiation, detect whether the current directory is a Compose project. - Construct the
Gui.
app.Run()→Gui.Run()— enter the gocui event loop.- On exit,
app.Close()closes the Docker client and any SSH tunnel.
2.4 Error handling at the top level
main.go distinguishes known errors from unexpected ones via
App.KnownError(). For example, the Docker "permission denied … socket" error
is rewritten into a friendly, translated message and exits cleanly (os.Exit(0))
rather than dumping a stack trace. Connection failures
(client.IsErrConnectionFailed) print the translated "connection failed"
message. Everything else is wrapped with a stack trace and logged via
log.Fatalf.
3. How Lazydocker Connects to Docker
Understanding host resolution is essential for remote and CI deployments.
3.1 Docker host resolution order
commands.determineDockerHost() resolves the daemon endpoint with this
precedence:
DOCKER_HOSTenvironment variable, if set.- The host bound to the current Docker context (selected via
DOCKER_CONTEXT, or the context store'scurrentContext). - The platform default socket:
- Unix/macOS:
unix:///var/run/docker.sock - Windows:
npipe:////./pipe/docker_engine
- Unix/macOS:
3.2 SSH hosts and tunneling
If the resolved host begins with ssh://, lazydocker:
- Exports it back to
DOCKER_HOST. - Invokes the SSH handler (
pkg/commands/ssh), which establishes a local Unix socket tunneled over SSH to the remote host.
This lets you drive a remote daemon transparently:
DOCKER_HOST=ssh://user@remote-host lazydocker
3.3 API version negotiation
The Docker client is built explicitly with WithAPIVersionNegotiation() and
without client.FromEnv. This is deliberate: FromEnv would honor
DOCKER_API_VERSION and lock the client version, breaking compatibility with
older daemons (the cause of the "client version 1.25 is too old" error). By
negotiating, lazydocker supports a wide range of daemon versions regardless of a
stray DOCKER_API_VERSION in the environment.
Important
Because lazydocker ignores
DOCKER_API_VERSIONby design, do not rely on that variable to force a version. If you must, the behavior is intentionally not honored for the SDK client.
4. Compose Project Detection and Scoping
Lazydocker behaves differently depending on whether it is operating inside a
Compose project. The predicate is DockerCommand.IsProjectScoped():
IsProjectScoped() == InDockerComposeProject OR (-p / ProjectName was set)
| Situation | Project scoped? | Effect |
|---|---|---|
Inside a compose dir, no -p |
Yes | Services + Project panels shown; containers filtered to project. |
Inside a compose dir, with -p |
Yes | Same, scoped to the named project. |
Outside a compose dir, no -p |
No | Services/Project panels hidden; all containers shown flat. |
Outside a compose dir, with -p |
Yes | Panels reappear; containers filtered to the named project. |
InDockerComposeProjectis determined at startup by running thecheckDockerComposeConfigtemplate (docker compose config --quiet). If it errors, the directory is not a compose context.- Services are derived two ways and merged: from
docker compose config --services(catches stopped services) and from container labels (com.docker.compose.service/.project, catches services across all projects). Compose-derived services win for the local project. - The local project name is resolved from container labels first, falling back to the launch directory's base name.
Note
The "outside compose dir +
-p" path is a deliberately supported case. It was silently disabled by an earlier refactor and restored; the regression testTestIsProjectScopedguards it.
5. Configuration Mastery
Lazydocker requires no configuration but exposes a deep config surface. This
section documents every key, its type, and its default. All keys are
optional and live in config.yml (see the User Guide for per-OS paths).
Caution
Config merging is shallow per top-level mapping. If you specify a parent key like
commandTemplates:but provide only some children, lazydocker keeps the defaults for the others — but providing an empty mapping under a key can scrap the defaults for that branch and may crash the app. Always provide complete values for any nested block you override.
5.1 gui — interface and appearance
| Key (YAML) | Type | Default | Meaning |
|---|---|---|---|
scrollHeight |
int | 2 |
Lines scrolled per keypress in the main panel. |
language |
string | "auto" |
UI language: auto, en, pl, nl, de, tr, fr, es, pt, zh. |
scrollPastBottom |
bool | false |
Allow scrolling past the end of the main view. |
mouseEvents |
bool | false¹ |
When true, ignore mouse events. (Field IgnoreMouseEvents.) |
theme.activeBorderColor |
[]string | ["green","bold"] |
Border color of the focused panel. |
theme.inactiveBorderColor |
[]string | ["default"] |
Border color of unfocused panels. |
theme.selectedLineBgColor |
[]string | ["blue"] |
Background of the selected line. |
theme.optionsTextColor |
[]string | ["blue"] |
Color of the options/footer text. |
showAllContainers |
bool | false |
Show every container (docker ps -a), not just those not tied to a service. |
returnImmediately |
bool | false |
Skip the "press enter to return" prompt after a subprocess exits. |
wrapMainPanel |
bool | true |
Word-wrap the main panel (higher CPU cost). |
legacySortContainers |
bool | false |
Sort containers by name (legacy) instead of by status. |
sidePanelWidth |
float | 0.3333 |
Side-panel width as a fraction of screen width. |
showBottomLine |
bool | true |
Show the bottom keybinding/status line. |
expandFocusedSidePanel |
bool | false |
Accordion effect: the focused side panel grows. |
screenMode |
string | "normal" |
Startup screen mode: normal, half, fullscreen. |
containerStatusHealthStyle |
string | "long" |
Status/health display: long (words), short (1–2 chars), icon (emoji). |
border |
string | "rounded" |
Window border style: rounded, single, double, hidden. |
¹ The default struct value is false (mouse events enabled). Set
mouseEvents: true to disable mouse handling.
5.2 logs — log rendering
| Key | Type | Default | Meaning |
|---|---|---|---|
timestamps |
bool | false |
Prefix log lines with timestamps. |
since |
string | "60m" |
How far back to fetch logs. "" means all logs. |
tail |
string | "" |
Limit to the last N lines (e.g. "200"). |
5.3 commandTemplates — the commands lazydocker runs
This is the most powerful customization point. Every Compose action is a Go
template; {{ .DockerCompose }} expands to the dockerCompose value, and
{{ .Service.Name }} / {{ .Project.Name }} are filled from context.
| Key | Default |
|---|---|
dockerCompose |
docker compose |
restartService |
{{ .DockerCompose }} restart {{ .Service.Name }} |
startService |
{{ .DockerCompose }} start {{ .Service.Name }} |
stopService |
{{ .DockerCompose }} stop {{ .Service.Name }} |
upService |
{{ .DockerCompose }} up -d {{ .Service.Name }} |
up |
{{ .DockerCompose }} up -d |
down |
{{ .DockerCompose }} down |
downWithVolumes |
{{ .DockerCompose }} down --volumes |
rebuildService |
{{ .DockerCompose }} up -d --build {{ .Service.Name }} |
recreateService |
{{ .DockerCompose }} up -d --force-recreate {{ .Service.Name }} |
serviceLogs |
{{ .DockerCompose }} logs --since=60m --follow {{ .Service.Name }} |
viewServiceLogs |
{{ .DockerCompose }} logs --follow {{ .Service.Name }} |
allLogs |
{{ .DockerCompose }} logs --tail=300 --follow |
viewAlLogs |
{{ .DockerCompose }} logs |
dockerComposeConfig |
{{ .DockerCompose }} config |
checkDockerComposeConfig |
{{ .DockerCompose }} config --quiet |
serviceTop |
{{ .DockerCompose }} top {{ .Service.Name }} |
Note
The
viewAlLogskey is spelled with a singlelin the source — this is the actual YAML key you must use. It is preserved here verbatim so your config matches what the application reads.
Tip
checkDockerComposeConfigis what lazydocker uses to decide whether the current directory is a Compose project. If detection misbehaves, this is the command to inspect.
If dockerCompose is left at its default docker compose, lazydocker probes
docker compose version at startup and silently falls back to docker-compose
if the v2 plugin is unavailable.
5.4 oS — opening files and links
| Key | Type | Default (Linux) | Default (macOS) | Default (Windows) |
|---|---|---|---|---|
openCommand |
string | sh -c "xdg-open {{filename}} >/dev/null" |
open {{filename}} |
cmd /c "start "" {{filename}}" |
openLinkCommand |
string | sh -c "xdg-open {{link}} >/dev/null" |
open {{link}} |
cmd /c "start "" {{link}}" |
These are used by the "open in browser" action (w) and any open-file flows.
{{filename}} and {{link}} are placeholder substitutions.
5.5 stats — graphs and collection window
| Key | Type | Default | Meaning |
|---|---|---|---|
maxDuration |
duration | 3m |
How long stat history is retained per container. |
graphs[].caption |
string | "CPU (%)", "Memory (%)" |
Graph label. |
graphs[].statPath |
string | DerivedStats.CPUPercentage, DerivedStats.MemoryPercentage |
Path into the recorded-stats struct. |
graphs[].color |
string | cyan, green |
Graph line color. |
graphs[].min / max |
float | — | Fixed axis bounds (set with minType/maxType: "static"). |
graphs[].minType / maxType |
string | "" |
"" = data-driven; "static" = use min/max. |
graphs[].height |
int | — | Graph height in characters. |
Valid statPath values come from the RecordedStats struct
(ClientStats.* for raw Docker stats, DerivedStats.* for computed values).
The Stats tab renders this struct as JSON so you can discover paths and
PascalCase them.
5.6 customCommands and bulkCommands
Both share the CustomCommand shape, grouped by object type (containers,
services, images, volumes, networks):
| Field (YAML) | Type | Meaning |
|---|---|---|
name |
string | Menu label. |
command |
string | Go-templated command. |
attach |
bool | Switch to the command as an interactive subprocess. |
shell |
bool | Run via a shell (/bin/bash -c "…"). |
serviceNames |
[]string | Restrict to specific services. |
bulkCommands apply to all items in a panel. Lazydocker ships default bulk
commands for services (up / up attached / stop / pull / build / down /
down-with-volumes / down-with-images / down-with-volumes-and-images). Containers
also have built-in bulk actions (stop all, remove all, prune).
Template variables available in commands: {{ .DockerCompose }},
{{ .Container }}, {{ .Service }}, {{ .Image }}, {{ .Volume }},
{{ .Network }}, {{ .Project }}.
5.7 replacements
| Key | Type | Meaning |
|---|---|---|
imageNamePrefixes |
map[string]string | Replace registry prefixes in displayed image names. |
5.8 Config directory resolution
config.NewAppConfig resolves the config directory via:
CONFIG_DIRenvironment variable, if set.- A legacy XDG path under vendor
jesseduffield, if it already exists. - The modern XDG config home.
The directory is created if missing, and an empty config.yml is created on
first run. Writes back to the config (via WriteToUserConfig) use omitempty,
so zero-valued settings are intentionally not persisted.
6. Security Analysis
Lazydocker's threat surface is small but its privilege level is high. Treat it as a privileged administrative tool.
6.1 Privilege model — the Docker socket is the crown jewel
Lazydocker has exactly the access its caller has to the Docker daemon. Access to the Docker socket is equivalent to root on the host: a user who can talk to the daemon can mount the host filesystem into a container and escalate. This is inherent to Docker, not specific to lazydocker, but it means:
Caution
Anyone who can run lazydocker against your daemon can start, stop, remove, and exec into any container, and can launch new privileged containers. Restrict Docker socket access to trusted administrators.
6.2 Arbitrary command execution via config
config.yml is effectively executable. Two surfaces run arbitrary commands:
commandTemplates— every value is a shell command lazydocker runs.customCommands/bulkCommands— user-defined commands, optionally via a shell (shell: true).- Editor invocation — pressing
eruns$VISUAL/$EDITOR(falling back tovi).
Warning
A malicious or compromised
config.ymlcan run arbitrary code with the user's privileges. Protect the config file's permissions and never load a config from an untrusted source. In shared or CI environments, pinCONFIG_DIRto a controlled location.
6.3 Remote hosts and credentials
DOCKER_HOST=ssh://…opens an SSH tunnel; SSH key handling is delegated to the local SSH agent/config, not managed by lazydocker.- TLS material for
tcp://hosts is read from the environment (WithTLSClientConfigFromEnv), following standard Docker conventions (DOCKER_TLS_VERIFY,DOCKER_CERT_PATH).
6.4 Secret handling in the UI
- The Env tab displays a container's environment variables verbatim, including any secrets baked into the container's environment. Be mindful when screen-sharing.
- The confirmation-panel code is explicitly written to never echo the original prompt in error messages, because prompts may contain sensitive input such as passwords.
6.5 No network exposure
Lazydocker opens no listening sockets and serves no API. Its only outbound
connections are to the Docker daemon (local socket, SSH tunnel, or TCP per your
DOCKER_HOST) and to the browser/editor it shells out to.
7. Operations
7.1 Deployment patterns
| Pattern | How | Notes |
|---|---|---|
| Local workstation | Install the binary; run lazydocker. |
Simplest; uses the local socket. |
| Team-standardized config | Distribute a config.yml to the per-OS path or pin CONFIG_DIR. |
Standardize themes, command templates, and custom commands. |
| Remote daemon over SSH | DOCKER_HOST=ssh://user@host lazydocker. |
Tunnel is created automatically. |
| Inside a container | Mount /var/run/docker.sock; mount a config volume. |
Logs/stats may not render; high privilege — trusted images only. |
| CI / scripted | Generally not applicable — lazydocker is interactive. | Use the docker/docker compose CLIs in CI instead. |
7.2 Logging and debugging
- Launch with
--debug(or setDEBUG=TRUE) to enable verbose logging via logrus. LOG_LEVELis honored by the logging package for finer control.- Debug logs are the first place to look when startup fails or a shelled-out command errors.
7.3 Upgrades
Lazydocker is a single binary; upgrading is replacing it. The provided
scripts/install_update_linux.sh re-downloads the latest release into
$HOME/.local/bin (or $DIR). Package-manager installs (Homebrew, Scoop,
Choco, AUR) upgrade through their normal channels. Config files are forward
compatible — new keys simply pick up defaults.
7.4 Backup and state
There is no application state to back up beyond config.yml. Version-control
your team's config.yml if you standardize one.
7.5 Environment variables reference
| Variable | Read by | Effect |
|---|---|---|
DOCKER_HOST |
determineDockerHost |
Explicit daemon endpoint (highest precedence). |
DOCKER_CONTEXT |
determineDockerHost |
Selects a Docker context's host. |
DOCKER_API_VERSION |
(intentionally not honored for the SDK client) | Ignored to preserve version negotiation. |
CONFIG_DIR |
configDirForVendor |
Override the config directory. |
DEBUG |
NewAppConfig |
TRUE enables debug mode. |
LOG_LEVEL |
pkg/log |
Sets log verbosity. |
VISUAL, EDITOR |
OSCommand.EditFile |
Editor for the e (edit config) action; falls back to vi. |
DIR |
install script | Target directory for the install/update script. |
DOCKER_TLS_VERIFY, DOCKER_CERT_PATH |
Docker SDK (WithTLSClientConfigFromEnv) |
TLS for tcp:// hosts. |
8. Internals for Contributors
8.1 Repository layout
lazydocker/
├── main.go Entry point: flags, build info, bootstrap
├── pkg/
│ ├── app/ app.go App wiring + known-error mapping
│ ├── config/ UserConfig, defaults, platform-specific OS config
│ ├── commands/ Docker SDK + OS command wrappers
│ │ ├── docker.go DockerCommand, host resolution, refresh logic
│ │ ├── container.go Container ops (start/stop/restart/pause/remove/top)
│ │ ├── container_stats.go Stats structs + CPU/memory derivation
│ │ ├── image.go Image ops + layer history
│ │ ├── service.go Compose service ops
│ │ ├── volume.go / network.go Volume/network ops
│ │ ├── os.go Shell runner, file/editor/link helpers
│ │ └── ssh/ SSH tunnel handler for ssh:// hosts
│ ├── gui/ gocui TUI: panels, keybindings, layout, tabs
│ │ ├── gui.go Gui struct, state, panel registry
│ │ ├── keybindings.go All keybindings (source of truth)
│ │ ├── arrangement.go boxlayout-based panel arrangement
│ │ ├── *_panel.go One file per panel + presentation/
│ │ └── tasks_adapter.go Bridges tasks to the GUI
│ ├── tasks/ tasks.go Cancellable background task manager
│ ├── i18n/ 9 translation sets
│ ├── log/ log.go Logrus setup
│ └── utils/ utils.go Templating, tables, colors, byte formatting
├── docs/
│ ├── Config.md User config reference
│ └── keybindings/ Auto-generated cheatsheets (9 languages)
└── scripts/cheatsheet/main.go Cheatsheet generator (generate | check)
8.2 The task system (concurrency model)
The GUI is event-driven, but logs and stats need continuous updates. The
tasks package provides cancellable tasks so that switching panels stops the
previous stream cleanly:
NewTickerTaskruns a function on an interval (logs poll every 200ms; stats and top every 1s) until its context is cancelled.NewSimpleRenderStringTaskrenders a one-shot string (env, config tabs).- An object cache key (e.g.
containers-<id>-<state>) determines when the main panel must re-run its render — for instance, restarting a container changes its state and forces logs to be re-read. - Stats are streamed from
Client.ContainerStatsin a background goroutine and appended to a per-container ring trimmed tostats.maxDuration.
8.3 Panel rendering pipeline
Each side panel is a generic SideListPanel[T] parameterized by the Docker
object type. A panel defines:
GetTableCells— how to render each row (via thepresentation/package).Filter— which items to show (e.g. project scoping, hide-exited).Sort— ordering (containers default to status order: running → exited → created;legacySortContainersswitches to name order).GetMainTabs— the main-panel tabs and their render functions.
The screen layout is computed by arrangement.go using the boxlayout package,
which arranges windows by weight/size and adapts to terminal size (including a
portrait mode for narrow terminals and a "limit" box for very small ones).
8.4 Keybindings as the source of truth
pkg/gui/keybindings.go (GetInitialKeybindings) is the canonical list of
bindings. A Binding ties a view name (empty = global), a key/rune, a modifier,
a handler, and a description. The cheatsheet files under docs/keybindings/ are
generated from these definitions plus the i18n descriptions by
scripts/cheatsheet/main.go generate; … check verifies they are up to date in
CI. When adding a binding, update the handler and run the generator.
8.5 Internationalization
pkg/i18n holds a TranslationSet per language (English is the base/reference).
gui.language: auto detects the system locale via jibber_jabber. User-facing
strings flow through gui.Tr.* so the cheatsheet generator and the UI stay in
sync.
8.6 Key dependencies
| Dependency | Role |
|---|---|
github.com/jesseduffield/gocui |
Terminal UI primitives (views, events, layout). |
github.com/docker/docker (SDK) |
Container/image/volume/network/stats operations. |
github.com/docker/cli |
Docker context/config loading for host resolution. |
github.com/jesseduffield/lazycore |
Shared layout (boxlayout) and utilities. |
github.com/integrii/flaggy |
CLI flag parsing. |
github.com/samber/lo |
Functional helpers (map/filter/find). |
github.com/sirupsen/logrus |
Logging. |
github.com/sasha-s/go-deadlock |
Deadlock-detecting mutexes (used on GUI/command state). |
github.com/jesseduffield/asciigraph |
ASCII stat graphs. |
github.com/imdario/mergo |
Merge command objects / config. |
9. Testing
The project uses Go's standard testing with stretchr/testify. Notable
coverage:
config/app_config_test.go— compose-file flag composition and round-tripping writes toconfig.yml.commands/docker_test.go— API-version negotiation regression (#715) and theIsProjectScopeddecision matrix.commands/container_stats_test.go— CPU-percentage calculation.gui/sort_container_test.go,gui/panels/filtered_list_test.go— sorting and filtering logic.
Run the suite with:
go test ./...
ok github.com/jesseduffield/lazydocker/pkg/commands 0.123s
ok github.com/jesseduffield/lazydocker/pkg/config 0.045s
ok github.com/jesseduffield/lazydocker/pkg/gui 0.210s
10. Potential Improvements
Observations from the source, useful for maintainers and contributors:
- Remappable keybindings. Bindings are compiled in (
keybindings.go). A config-driven keymap (as in lazygit) is a frequently desired feature. - Stats container-in-container. Logs/stats not rendering when lazydocker runs inside a container is a known limitation worth documenting in-app or detecting and warning about.
- Service logs vs container logs.
serviceLogsis defined but the app currently shows the corresponding container's logs; explicit multi-container service log aggregation is noted as a TODO in the source. O(N*M)container/service filtering. The project-scoped container filter iterates services × containers; fine for typical sizes but flagged in comments as something to watch for large deployments.- Compose profile support (
#423) and column sorting in panels (#384) are open community requests.
11. Quick Reference
| Need | Where |
|---|---|
| Default config dump | lazydocker --config |
| Config file (Linux) | ~/.config/lazydocker/config.yml |
| Config file (macOS) | ~/Library/Application Support/jesseduffield/lazydocker/config.yml |
| Config file (Windows) | %APPDATA%\lazydocker\config.yml |
| Override config dir | CONFIG_DIR env var |
| Remote daemon | DOCKER_HOST=ssh://user@host lazydocker |
| Debug logging | lazydocker --debug or DEBUG=TRUE |
| Scope to a project | lazydocker -p <name> |
| Combine compose files | lazydocker -f a.yml -f b.yml |
| Keybinding source | pkg/gui/keybindings.go |
| Regenerate cheatsheets | go run scripts/cheatsheet/main.go generate |
| Requirements | Docker ≥ 29.0.0 (API ≥ 1.24); Compose ≥ 1.23.2 (optional) |