# lazydocker: one terminal window over docker and docker-compose, with its own bundled CLI

> A Go terminal UI built on gocui that puts container state and common commands behind a keyboard map. It talks to the engine by mounting the Docker socket and ships a docker CLI it builds itself, which is where most of its rough edges come from.

**jesseduffield/lazydocker** — The lazier way to manage everything docker

- Repository: https://github.com/jesseduffield/lazydocker
- Stars: 52,975 · Forks: 1,686
- Language: Go
- License: MIT
- Published: 2026-08-17 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/jesseduffield-lazydocker

## The pitch is about forgetting commands, and it hands you a keymap instead

The elevator pitch is a story about losing time rather than a feature list. Something is broken, so you run `docker-compose ps`, restart the service, and the issue is still there, because the service died right after starting and the log stream is buried under output from everything else. Following one service's logs with `docker compose logs --follow myservice` dies each time that service dies, and leaving `docker-compose up myservice` running in a window means one service owns a terminal even when you stop caring about its output. The argument ends with a diagnosis: memorising docker commands is hard, aliases are slightly less hard, and tracking containers across windows is near impossible. The stated goal is all of that information in one window with every common command a keypress away, and room to add your own. The cost is a keyboard-driven UI with its own bindings, listed under Keybindings in the page's own table of contents.

## lazydocker builds its own docker CLI and pins two different versions of it

The repository does not shell out to the docker binary on your PATH. The Dockerfile has a dedicated stage that installs build tooling, clones the CLI source, and builds it:

```
ARG DOCKER_VERSION=v27.0.3
RUN git clone --branch ${DOCKER_VERSION} --single-branch --depth 1 https://github.com/docker/cli.git . > /dev/null 2>&1
```

The resulting binary is kept alone, with every other platform variant removed, and the final image copies it to /bin/docker next to the entrypoint:

```
FROM scratch
ENTRYPOINT [ "/bin/lazydocker" ]
```

Meanwhile go.mod pins github.com/docker/cli at v27.1.1 and github.com/docker/docker at v28.5.2. So two version numbers for the same tool live in the same repository and they disagree. What lazydocker cannot do is guarantee that a command behaves the way the identical command behaves in your terminal, because the CLI answering it is a pinned build from 2024 vintage, not the one you installed. If a flag misbehaves through the UI, check that version gap before you file a bug about the interface.

## The compose file hands the host Docker socket to the container in two lines

The distribution compose file is short enough to read in full, and its volumes are the part that deserves attention:

```
volumes:
  - /var/run/docker.sock:/var/run/docker.sock
  - ./config:/.config/jesseduffield/lazydocker
```

Everything lazydocker knows about your containers, it learns through that first mount, which is the same socket your own docker command uses. The consequence is straightforward: a process with that socket can do what the daemon can do, and the daemon runs containers as root on the host, so running lazydocker in a container is closer to handing over a root shell than handing over a config file. That is why the file also sets `stdin_open: true` and `tty: true`, since it is meant to be driven interactively. Note the second mount writes to a path rooted at /.config inside the container, and note the build pins `GOARCH: amd64` with an empty `GOARM`, so the image as written is an amd64 build rather than a multi architecture one.

## The last image stage is FROM scratch, so every dependency has to be copied in by hand

The build compiles the Go binary with the module graph vendored and the version stamped in at link time:

```
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${GOARCH} GOARM=${GOARM} \
    go build -a -mod=vendor \
    -ldflags="-s -w \
    -X main.commit=${VCS_REF} \
    -X main.version=${VERSION} \
    -X main.buildSource=Docker"
```

Those injected values are what the opencontainers labels and the about output read, and the build source is recorded as Docker rather than as a release build, which is a small but useful signal when you are looking at a running container and wondering which artifact it is. The consequence of the scratch stage is that the final image has no shell and no userland, so the only two binaries visible in the copy lines are the app and the docker CLI. Anything else a command needs must be copied in deliberately, and a failure anywhere in the second stage, where the CLI is compiled from source, stops the whole image from building even though the app itself compiled fine.

## The examples use both docker-compose and docker compose, and the detach key is left unresolved

Read the pitch closely and the spellings change halfway through. Status, restart, and up all appear in the hyphenated form, while the log command appears in the spaced form:

```
docker-compose ps
docker compose logs --follow myservice
```

Those are two different command line parsers, one from the standalone Compose v1 binary and one from the Compose v2 plugin, and nothing on the page explains the switch. The consequence for a reader is that the examples cannot be pasted blindly: run the hyphenated spelling on a machine that only ships the plugin and it fails, and vice versa. The same passage leaves the exit gesture unresolved, asking whether the prefix sequence detaches from a compose session and then wondering whether Ctrl+C closes the foreground process or kills the service. No answer is given, and the page defers to its own Keybindings document for that, so treat the narrative as a description of the problem rather than as the manual.

## A vendored tree, a committed coverage file, and three releases between January and April

The repository's top level tells you how the project is worked on. There is a vendor/ directory, and the build runs with -mod=vendor, so the checked out dependency tree is the one that compiles rather than whatever a proxy serves later. The go directive reads 1.22 with a toolchain line of go1.23.6, and the module depends on the Docker SDK directly alongside a maintained fork of gocui, which is where the terminal interface comes from. Alongside that sit .golangci.yml for linting, test.sh and a test/ directory, a coverage.txt committed at the root, a .devcontainer/, a .circleci/ directory, and a .goreleaser.yml for release packaging. The release history is short: v0.24.4 on 2026-01-17, v0.25.0 on 2026-03-15, and v0.25.2 on 2026-04-19, and the last push to master is dated 2026-04-19. So expect a pace of a release every few weeks with no change since April.

## Custom commands are promised, and the config directory is what travels with the run

One of the two things the pitch asks for is not built in. Alongside putting common commands a keypress away, it names the ability to add custom commands, and the repository ships a config/ directory at the top level. The compose file mounts that host directory into the container, so whatever you place in it goes with every run, on the host rather than inside the image, which is the arrangement you want for settings and definitions that change per project. What the page does not do is describe that directory: the visible text does not document a config file format, a list of recognised keys, or what a custom command receives when it runs. The consequence is that extending lazydocker is a read the source exercise rather than a documented configuration task, so budget for it, and assume the mounted directory is the interface.

## Conclusion

lazydocker suits someone who lives in a terminal, drives docker compose from a laptop, and wants container state plus common commands behind a single keymap. It does not suit a team that needs a recently reviewed UI layer, a documented Windows install path, or parity with the docker CLI already on their PATH, since the last commit landed on 2026-04-19 and the bundled CLI is compiled from v27.0.3. Before adopting, decide whether handing the Docker socket to a container is acceptable on that host, and check which docker compose spelling your machine actually provides, because the examples use both forms.

## FAQ

### What is lazydocker?

It is a simple terminal UI for both docker and docker-compose, written in Go with the gocui library, released under the MIT licence. Its stated goal is to put container information in one terminal window with common commands a keypress away, plus room for custom commands.

### how to install lazydocker

The visible page links to the GitHub releases and to a Homebrew core formula file rather than printing an install command, and the repository ships a docker-compose.yml that builds the image lazyteam/lazydocker from the git context. That compose file mounts the Docker socket and the local config directory, so it is a way to run the tool rather than a package install.

### how to use lazydocker

The interface is keyboard driven, and the page's table of contents points to a Keybindings document for the bindings themselves. The described workflow is to see all container state in one window instead of spreading commands across terminal windows, with common commands one keypress away.

### lazydocker vs docker

lazydocker is not a container runtime, it is a terminal front end over docker and docker-compose. It reaches the engine through the Docker socket and drives a docker CLI that the project compiles itself at v27.0.3 rather than using the one on your PATH.

### How do I install Lazydocker on Windows?

The visible page does not document a Windows install path. It points to GitHub releases and to a Homebrew core formula, and the module's dependency list includes Microsoft/go-winio, though nothing on the page states a Windows support policy.

## Sources

- [Official README](https://github.com/jesseduffield/lazydocker#readme)
- [Project repository](https://github.com/jesseduffield/lazydocker)
- [Release notes](https://github.com/jesseduffield/lazydocker/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/jesseduffield-lazydocker
