Jesse A. Green / notebook

dive User Guide

Generated June 2026 from wagoodman/dive at d6c6919

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

dive is a terminal tool for exploring a Docker or OCI image one layer at a time and discovering wasted space so you can make your images smaller. You point it at an image, and it opens an interactive two-pane view: the image's layers on the left, and the combined file tree on the right. As you move between layers, you see exactly which files each Dockerfile instruction added, changed, or removed — and an "efficiency" score that estimates how much space is being wasted by files that are duplicated, moved, or deleted across layers.

It runs in two modes:

  • Interactive mode — a full-screen terminal UI (TUI) for browsing layers and files by hand.
  • CI mode — no UI; analyze an image and return a pass/fail exit code based on efficiency rules, so a pipeline can block bloated images.

Note

dive does not change your images. It reads them (from a container engine or a tar archive), analyzes them in memory, and renders the result. Nothing is written back to the image.


1. Quick Start

Analyze an existing image by tag, ID, or digest:

dive <your-image-tag>

For example:

dive nginx:latest
  ● Loading image... done
  ● Analyzing image... done
    (the interactive UI opens)

When the UI opens:

  • Use ↑/↓ to move through layers (left pane).
  • Press Tab to jump to the file tree (right pane) and explore the filesystem at that layer.
  • Press Ctrl+C (or Q) to quit.

Tip

No image on your machine yet? dive will pull it through your container engine first, the same way docker run would. Large images can take a while to fetch — dive prints this can take a while for large images... after a few seconds so you know it is still working.

Build and analyze in one step

If you are iterating on a Dockerfile, you can build the image and drop straight into analysis without a separate docker build:

dive build -t my-app:latest .

This is a thin wrapper around docker build — replace docker build with dive build and pass the exact same arguments.

Analyze in CI (no UI)

Set CI=true (or pass --ci) to skip the UI and get a pass/fail result instead:

CI=true dive my-app:latest
Analysis:
  efficiency:        98.45 %
  wastedBytes:       1485633 bytes (1.5 MB)
  userWastedPercent: 12.00 %

Evaluation:
  PASS  highestUserWastedPercent
  FAIL  lowestEfficiency (image efficiency is too low (efficiency=0.98 < threshold=...))

FAIL [pass:1 fail:1]

A failing rule makes dive exit with a non-zero status, which fails the pipeline step.


2. Installation

dive ships as a single self-contained binary for Linux, macOS, and Windows. Pick the method that matches your platform.

Important

dive analyzes images through a container engine (Docker or Podman) or from a tar archive. For the default Docker workflow you need a working Docker engine that your user can talk to. See Requirements below.

Ubuntu / Debian (.deb)

DIVE_VERSION=$(curl -sL "https://api.github.com/repos/wagoodman/dive/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
curl -fOL "https://github.com/wagoodman/dive/releases/download/v${DIVE_VERSION}/dive_${DIVE_VERSION}_linux_amd64.deb"
sudo apt install ./dive_${DIVE_VERSION}_linux_amd64.deb

RHEL / CentOS / Fedora (.rpm)

DIVE_VERSION=$(curl -sL "https://api.github.com/repos/wagoodman/dive/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
curl -fOL "https://github.com/wagoodman/dive/releases/download/v${DIVE_VERSION}/dive_${DIVE_VERSION}_linux_amd64.rpm"
rpm -i dive_${DIVE_VERSION}_linux_amd64.rpm

Arch Linux

pacman -S dive

macOS (Homebrew)

brew install dive

macOS (MacPorts)

sudo port install dive

Windows (Chocolatey)

choco install dive

Windows (Scoop)

scoop install main/dive

Windows (winget)

winget install --id wagoodman.dive

Nix / NixOS

# NixOS
nix-env -iA nixos.dive
# non-NixOS (Linux, Mac)
nix-env -iA nixpkgs.dive

Go tools

go install github.com/wagoodman/dive@latest

Caution

Snap users, read this. A Snap package exists (sudo snap install dive), but it is not recommended if you installed Docker via apt-get — it can break your existing Docker daemon. The Snap also requires manual interface connections:

sudo snap install docker
sudo snap install dive
sudo snap connect dive:docker-executables docker:docker-executables
sudo snap connect dive:docker-daemon docker:docker-daemon

This is the cause of the common "no images found after snap install dive" problem. If you use Docker from apt, prefer the .deb package instead.

Note

Installing with go install works, but the binary will not report a proper version with dive --version (the version is injected at release build time, not by go install).

Run as a Docker container (no install)

You can run dive itself as a container. Because it talks to your Docker engine, you must mount the Docker socket:

docker run --rm -it \
    -v /var/run/docker.sock:/var/run/docker.sock \
    docker.io/wagoodman/dive:latest <dive arguments...>

A convenient shell alias:

alias dive="docker run -ti --rm -v /var/run/docker.sock:/var/run/docker.sock docker.io/wagoodman/dive"
dive nginx:latest

The image is published to both registries:

docker pull docker.io/wagoodman/dive
# or
docker pull ghcr.io/wagoodman/dive

Tip

Depending on your local Docker version you may need to pin the API version so the containerized dive can talk to your daemon:

docker run --rm -it \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -e DOCKER_API_VERSION=1.37 \
    docker.io/wagoodman/dive:latest <dive arguments...>

Verify the install

dive --version
dive 0.x.x

3. Requirements

Requirement Why you need it Notes
A container engine — Docker or Podman dive fetches and (for build) builds images through an engine Docker is the default. Podman is supported on Linux and macOS only.
Access to the Docker socket The default docker source reads images from the running daemon Typically /var/run/docker.sock. Containerized dive must mount it.
The docker (or podman) client binary on your PATH dive build shells out to the real docker build / podman build If missing, you get cannot find docker client executable.
A terminal that supports a full-screen TUI Interactive mode draws panes, colors, and borders Not needed in CI mode (--ci / CI=true).

Note

If you only have an image tar archive on disk (for example exported by docker save or produced by a build tool like Kaniko), you do not need a running engine at all — use the docker-archive source described in Choosing where the image comes from.


4. Everyday Usage

4.1 Analyzing an image

The most common command is simply the image reference:

dive <image>

<image> can be a tag, an ID, or a digest:

dive nginx:latest
dive 1f2c1c8a0e3b
dive nginx@sha256:ad9fa4d07136a83e69a54ef00102f579d04eba431932de3b0f098cc5d5948f9f

4.2 Choosing where the image comes from

By default dive reads from the Docker engine. To pull from a different source, either pass --source or prefix the image with a source:// scheme. The two forms are equivalent:

dive <image> --source <source>
# or
dive <source>://<image>
Source Meaning Availability
docker Read from the Docker engine (the default) All platforms
docker-archive Read a Docker/OCI tar archive from disk All platforms
podman Read from the Podman engine Linux and macOS only

Examples:

# from the Docker engine (default — both are the same)
dive nginx:latest
dive docker://nginx:latest

# from a tar archive on disk
dive --source docker-archive ./my-image.tar
dive docker-archive://./my-image.tar

# from Podman
dive --source podman localhost/my-app:dev
dive podman://localhost/my-app:dev

Note

docker-tar is accepted as an alias for docker-archive.

Warning

If you pass an invalid value to --source, dive warns and falls back to docker: invalid container engine: <value> (valid options: docker, podman, docker-archive), using default "docker".

4.3 Building and analyzing together

dive build [any valid "docker build" arguments]

dive build runs your build through the engine and then analyzes the result. Everything after build is passed verbatim to docker build:

dive build -t my-app:latest .
dive build -t my-app:latest -f Dockerfile.prod --build-arg ENV=prod .

Important

Because build forwards all arguments straight to docker build, dive-specific flags do not work after build. Configure dive's behavior for build runs through a config file or environment variables (for example CI=true dive build -t my-app .), not through flags like --source placed after build.

On macOS (Docker engine only), mount your working directory and config when running the container form:

docker run --rm -it \
      -v /var/run/docker.sock:/var/run/docker.sock \
      -v "$(pwd)":"$(pwd)" \
      -w "$(pwd)" \
      -v "$HOME/.dive.yaml":"$HOME/.dive.yaml" \
      docker.io/wagoodman/dive:latest build -t my-app:latest .

4.4 Continuing past parse errors

If an image archive has entries dive cannot parse, the run normally stops. To analyze what it can read and keep going, use --ignore-errors:

dive my-image:latest --ignore-errors
# short form
dive my-image:latest -i

4.5 Exporting the analysis as JSON

To capture the analysis as a machine-readable file (and skip the UI entirely), use --json:

dive my-app:latest --json analysis.json
# short form
dive my-app:latest -j analysis.json

The file contains per-layer file lists plus image-level totals — overall size, wasted bytes, efficiency score, and the list of inefficient files:

{
  "layer": [
    {
      "index": 0,
      "id": "...",
      "digestId": "sha256:...",
      "sizeBytes": 5560320,
      "command": "FROM ...",
      "fileList": [ /* per-file metadata */ ]
    }
  ],
  "image": {
    "sizeBytes": 14830080,
    "inefficientBytes": 1485633,
    "efficiencyScore": 0.9845,
    "fileReference": [
      { "count": 2, "sizeBytes": 1048576, "file": "/var/cache/app/data" }
    ]
  }
}

Warning

The directory you write to must already exist, or dive stops with directory for JSON export does not exist: <dir>.


5. Reading the Interactive UI

The screen is split into a layer pane (left) and a file tree pane (right), with layer/image details and a status bar.

  • Layer pane (left). Each row is one image layer, showing its size and the command (Dockerfile instruction) that created it. Select a layer to see its contents on the right.
  • File tree pane (right). Shows the filesystem as of the selected layer, combined with all layers below it. Files are color-coded by how they changed in the selected layer.
  • Details panes. Below the layer list you get layer details, image details, and the efficiency report (efficiency score and estimated wasted space).

What the colors mean

Color Change type Meaning
Green Added The file is new in this layer
Yellow Modified The file's contents or attributes changed in this layer
Red Removed The file was deleted in this layer
Default Unmodified The file is unchanged from a lower layer

Tip

Use Ctrl+A in the layer view to see aggregated changes (everything modified from the first layer up to the selected one), and Ctrl+L to see only the current layer's changes.


6. Keyboard Shortcuts

These are the default bindings. Every one of them can be remapped in a config file — see Customizing keybindings.

Key Action
Ctrl+C or Q Quit
Tab Switch between the layer and file tree views
Ctrl+F Filter files by name
Esc Close the file filter
↑ or K Move up one line
↓ or J Move down one line
← or H Move to the previous pane / left
→ or L Move to the next pane / right
PageUp or U Scroll up a page
PageDown or D Scroll down a page

Layer view only

Key Action
Ctrl+A Show aggregated image modifications (all layers up to this one)
Ctrl+L Show only the current layer's modifications

File tree view only

Key Action
Space Collapse / uncollapse the selected directory
Ctrl+Space Collapse / uncollapse all directories
Ctrl+A Show / hide added files
Ctrl+R Show / hide removed files
Ctrl+M Show / hide modified files
Ctrl+U Show / hide unmodified files
Ctrl+B Show / hide file attributes (permissions, owner, size)

Note

A few additional actions exist as configurable bindings even though they have no default key assigned in the shipped table: toggling the file sort order, toggling tree wrapping, and extracting a file's contents. You can bind keys to them in the keybinding: section of your config (see below). Some bindings — like the file filter — accept multiple keys; the first key listed is the one shown in the UI hint.


7. Configuration

dive works with zero configuration. A config file is only needed when you want to change defaults — display preferences, CI rules, or keybindings.

7.1 Where config files live

dive searches these locations, in order, and accepts .yaml or .yml:

  • $XDG_CONFIG_HOME/dive/*.yaml
  • $XDG_CONFIG_DIRS/dive/*.yaml
  • ~/.config/dive/*.yaml
  • ~/.dive.yaml

You can also point at a specific file two ways:

# explicit config flag
dive nginx:latest -c ./my-dive.yaml

# or via environment variable
DIVE_CONFIG=./my-dive.yaml dive nginx:latest

To see the configuration dive actually resolved (defaults merged with your file), run:

dive config

7.2 Display preferences

A complete UI config file, with the built-in defaults shown:

# which engine to read images from: "docker" or "podman"
container-engine: docker

# continue analysis even if the image archive has parse errors
ignore-errors: false

log:
  enabled: true
  path: ./dive.log
  level: info

diff:
  # file change types to hide in the tree by default.
  # valid values: added, removed, modified, unmodified
  hide:
    - added
    - removed

filetree:
  # start with directories collapsed
  collapse-dir: false
  # fraction of screen width for the file tree pane (must be >0 and <1)
  pane-width: 0.5
  # show file attributes (permissions/owner/size) next to the tree
  show-attributes: true

layer:
  # show changes aggregated across all previous layers by default
  show-aggregated-changes: false
Key Default Meaning
container-engine docker Engine to read images from (docker or podman)
ignore-errors false Keep analyzing past archive parse errors
diff.hide (none — all shown) Change types hidden in the tree by default
filetree.collapse-dir false Start with directories collapsed
filetree.pane-width 0.5 File tree pane width as a fraction of the screen
filetree.show-attributes true Show permission/owner/size columns
layer.show-aggregated-changes false Default to aggregated vs. single-layer changes

Warning

filetree.pane-width must be strictly between 0 and 1. If you set it to 0, 1, or outside that range, dive warns and resets it to 0.5.

Note

diff.hide values are validated. An unrecognized entry produces a warning like invalid diff hide value: <value> (valid values: added, removed, modified, unmodified) and is ignored.

7.3 Customizing keybindings

Every action's keys live under keybinding:. Separate multiple keys with a comma; the first key is the one shown in the UI hint.

keybinding:
  # Global
  quit: ctrl+c
  toggle-view: tab
  filter-files: ctrl+f, ctrl+slash
  close-filter-files: esc
  up: up,k
  down: down,j
  left: left,h
  right: right,l

  # Layer view
  compare-all: ctrl+a
  compare-layer: ctrl+l

  # File tree view
  toggle-collapse-dir: space
  toggle-collapse-all-dir: ctrl+space
  toggle-added-files: ctrl+a
  toggle-removed-files: ctrl+r
  toggle-modified-files: ctrl+m
  toggle-unmodified-files: ctrl+u
  toggle-filetree-attributes: ctrl+b
  page-up: pgup,u
  page-down: pgdn,d

8. Using dive in CI

CI mode turns dive into a gate: it analyzes the image, checks it against efficiency rules, and exits non-zero if a rule fails — no interactive UI.

8.1 Turning on CI mode

Either set the environment variable or pass the flag:

CI=true dive my-app:latest
# or
dive my-app:latest --ci

CI=true (also 1 or yes) enables it from the environment; --ci enables it explicitly.

8.2 The three rules

CI evaluates up to three rules. Each can be a number or the literal disabled (also off/false/empty) to skip it.

Rule Fails when Built-in default
lowest-efficiency Efficiency drops below this ratio (0–1) 0.9
highest-wasted-bytes Wasted space is at or above this size (e.g. 20MB, 100kB) disabled
highest-user-wasted-percent Wasted space is at or above this fraction (0–1) of user-added bytes 0.1

Note

These are the defaults baked into dive when no .dive-ci file is present. A .dive-ci file you write replaces them with whatever you specify.

8.3 The .dive-ci rules file

Put a .dive-ci file at the root of your repo (this is the default path; override it with --ci-config):

rules:
  # fail if efficiency is below 95%
  lowest-efficiency: 0.95
  # fail if wasted space is 20 MB or more
  highest-wasted-bytes: 20MB
  # fail if 20% or more of user-added bytes are wasted
  highest-user-wasted-percent: 0.20
dive my-app:latest --ci --ci-config ./.dive-ci

Note

Older configs used camelCase keys (lowestEfficiency, highestWastedBytes, highestUserWastedPercent). These still load, but dive warns that they are deprecated — prefer the snake-case names above.

Tip

Wasted-space sizes accept human units: B, kB, MB, GB (e.g. highest-wasted-bytes: 20MB).

8.4 In a Docker-based pipeline

docker run --rm -t \
  --env CLICOLOR_FORCE=true \
  -v /var/run/docker.sock:/var/run/docker.sock \
  docker.io/wagoodman/dive:latest \
    my-app:latest \
    --ci

Important

CI runs still need access to the image. Mount the Docker socket (as above), or analyze a tar archive with --source docker-archive so no engine is required.


9. Common Tasks

Find the biggest space wasters in an image

dive my-app:latest

Read the efficiency report pane. Then in the file tree, press Ctrl+U to hide unmodified files and Ctrl+A in the layer view to see aggregated changes — duplicated/removed files stand out.

Gate a build in CI on image efficiency

# .dive-ci at repo root, then:
CI=true dive my-app:latest

Analyze an image that is not in your engine (only a tar on disk)

docker save my-app:latest -o my-app.tar
dive --source docker-archive my-app.tar

Capture results for later or for another tool

dive my-app:latest --json analysis.json

Hide the noise and focus on what each layer added

# ~/.dive.yaml
diff:
  hide:
    - unmodified

10. Troubleshooting

Error: cannot find docker client executable

Cause. dive build (or the Docker source) cannot find the docker binary on your PATH. Solution. Install the Docker client and ensure it is on PATH. In the containerized dive, make sure you are using an image/tag that bundles the client, and mount the socket. Prevention. Run docker version first — if that fails, dive will too.

Error: could not find image config

Cause. The image archive is missing its config blob, or is in a format dive could not fully parse (reported in issue #452). Often seen with unusual builders or partial archives. Solution. Re-export the image (docker save), or pull a fresh copy. If you only need a partial analysis, add --ignore-errors. Prevention. Analyze images produced by a standard docker build/docker save or a current OCI exporter.

Error: could not find Containerfile or Dockerfile

Cause. dive build was pointed at a directory that has no Dockerfile or Containerfile. Solution. Run dive build from a directory containing a build file, or pass -f <path> to point at one. Prevention. Confirm the build context is correct, exactly as you would for docker build.

Error: unable to determine image resolver

Cause. The source could not be resolved — usually an invalid --source value or an unrecognized scheme:// prefix. Solution. Use one of docker, docker-archive, or podman. Check the source://image spelling. Prevention. Stick to the documented sources in section 4.2.

Error: cannot find podman client executable

Cause. You selected the podman source but Podman is not installed or not on PATH. Solution. Install Podman (Linux/macOS only) or switch to the Docker source. Prevention. dive does not support Podman on Windows.

No images appear after installing via Snap

Cause. The Snap package needs its Docker interfaces connected, and conflicts with a Docker installed via apt (issue #546). Solution. Connect the interfaces (snap connect dive:docker-executables docker:docker-executables and dive:docker-daemon docker:docker-daemon), or uninstall the Snap and use the .deb package. Prevention. If Docker came from apt, do not use the Snap build of dive.

The wrong Docker host is used on Windows

Cause. On Windows / alternative runtimes the default Docker host can be detected incorrectly (issue #649). Solution. Set DOCKER_HOST explicitly. With Colima or similar:

export DOCKER_HOST=$(docker context inspect -f '{{ .Endpoints.docker.Host }}')

Prevention. Export DOCKER_HOST in your shell profile when using a non-standard runtime.

dive hangs right after the main view opens

Cause. A known race condition when starting in some terminals/containers (issue #513). Solution. Resize the terminal or relaunch; ensure your terminal is a real TTY (for the container form, pass -it). Prevention. Run interactive mode in a proper terminal; use CI mode in non-interactive environments.

The containerized dive cannot reach the daemon

Cause. Docker API version mismatch between the container and your host daemon. Solution. Pin the API version:

DOCKER_API_VERSION=1.37 dive ...
# or with the container form, add: -e DOCKER_API_VERSION=1.37

Prevention. Set DOCKER_API_VERSION when host and client versions differ.

dive --version shows no real version

Cause. You installed via go install, which does not inject build-time version info. Solution. Install a released binary (package manager or releases page) if you need an accurate version string. Prevention. Use packaged releases for production use.


11. FAQ

Q: Does dive modify or rebuild my image? No. It reads the image (from an engine or a tar) and analyzes it in memory. The only command that creates anything is dive build, which runs your docker build and then analyzes the result.

Q: What exactly is the "efficiency" score? It is an estimate of how much of your image's bytes are "necessary." Roughly: for every file path, dive compares the smallest version of that file it ever saw against the total bytes that path consumed across all layers. Files that are duplicated, moved, or deleted across layers drag the score down. A score near 100% means almost no wasted space.

Q: What counts as "wasted" space? Bytes spent on files that appear in more than one layer, or that are added and then removed in a later layer. The base image layer is excluded from the "user wasted percent" calculation.

Q: Can I use dive without Docker? Yes — analyze a tar archive with --source docker-archive ./image.tar, which needs no running engine. You can also use Podman on Linux/macOS.

Q: Does dive work with Podman on Windows? No. Podman support is Linux and macOS only. Use the Docker source on Windows.

Q: How do I run dive headless in a pipeline? Set CI=true (or pass --ci). This skips the UI and returns a pass/fail exit code based on your .dive-ci rules.

Q: My --source docker flag after build is ignored. Why? dive build forwards everything after build to docker build, so dive flags placed there are passed to Docker, not dive. Configure build-run behavior via a config file or environment variables instead.

Q: Can I change the keyboard shortcuts? Yes. Remap any action under the keybinding: section of your config file. Multiple keys per action are allowed (comma-separated); the first is shown in the UI hint.

Q: How do I make dive keep going when an image has unreadable entries? Add --ignore-errors (-i). It analyzes what it can and skips the rest.

Q: Where should I put the CI rules file? A .dive-ci file at the repo root is picked up automatically. Use --ci-config <path> to point elsewhere.

Q: Can I get the analysis as data instead of a UI? Yes — dive <image> --json <file> writes per-layer file lists and image-level totals (size, wasted bytes, efficiency, inefficient files) as JSON.


12. Command & Flag Reference

Commands

Command Purpose
dive [IMAGE] Fetch and analyze an image; open the UI (or run CI checks)
dive build [docker build args] Build an image via docker build, then analyze it
dive version Print version information
dive config Print the resolved configuration

Flags (root and build)

Flag Short Default Purpose
--source <engine> docker Where to read the image from: docker, docker-archive, podman
--ignore-errors -i false Continue analysis past image parse errors
--ci false Skip the UI and validate against CI rules (same as CI=true)
--ci-config <path> .dive-ci Rules file to use in CI mode
--json <file> -j Write the layer analysis to a JSON file and skip the UI
--lowestEfficiency <ratio> (only with --ci) override the lowest-efficiency rule
--highestWastedBytes <size> (only with --ci) override the highest-wasted-bytes rule
--highestUserWastedPercent <ratio> (only with --ci) override the highest-user-wasted-percent rule
--config <path> -c Use a specific config file
--help -h Show help

Note

--help on the root command also prints the full resolvable application configuration, so you can see every setting and its current value at a glance.

Environment variables

Variable Effect
CI true/1/yes enables CI mode
DIVE_CONFIG Path to a config file to load
DOCKER_HOST Docker daemon endpoint (useful with Colima/Rancher/Podman-machine)
DOCKER_API_VERSION Pin the Docker API version for client/daemon compatibility
DOCKER_TLS_VERIFY Enable TLS verification against the Docker daemon
DOCKER_CONTEXT Select a Docker context
CLICOLOR_FORCE true forces colored output (handy inside CI containers)