# dive User Guide

`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:

```bash
dive <your-image-tag>
```

For example:

```bash
dive nginx:latest
```

```text
  ● Loading image... done
  ● Analyzing image... done
    (the interactive UI opens)
```

When the UI opens:

- Use <kbd>↑</kbd>/<kbd>↓</kbd> to move through layers (left pane).
- Press <kbd>Tab</kbd> to jump to the file tree (right pane) and explore the filesystem at that layer.
- Press <kbd>Ctrl</kbd>+<kbd>C</kbd> (or <kbd>Q</kbd>) 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`:

```bash
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:

```bash
CI=true dive my-app:latest
```

```text
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](#3-requirements) below.

=== "Ubuntu / Debian (.deb)"

    ```bash
    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)"

    ```bash
    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"

    ```bash
    pacman -S dive
    ```

=== "macOS (Homebrew)"

    ```bash
    brew install dive
    ```

=== "macOS (MacPorts)"

    ```bash
    sudo port install dive
    ```

=== "Windows (Chocolatey)"

    ```powershell
    choco install dive
    ```

=== "Windows (Scoop)"

    ```powershell
    scoop install main/dive
    ```

=== "Windows (winget)"

    ```powershell
    winget install --id wagoodman.dive
    ```

=== "Nix / NixOS"

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

=== "Go tools"

    ```bash
    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:
>
> ```bash
> 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:

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

A convenient shell alias:

```bash
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:

```bash
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:
>
> ```bash
> 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

```bash
dive --version
```

```text
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](#42-choosing-where-the-image-comes-from).

---

## 4. Everyday Usage

### 4.1 Analyzing an image

The most common command is simply the image reference:

```bash
dive <image>
```

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

```bash
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:

```bash
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:

```bash
# 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

```bash
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`:

```bash
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:

```bash
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`:

```bash
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`:

```bash
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:

```json
{
  "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 <kbd>Ctrl</kbd>+<kbd>A</kbd> in the layer view to see **aggregated** changes (everything modified from the first layer up to the selected one), and <kbd>Ctrl</kbd>+<kbd>L</kbd> 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](#73-customizing-keybindings).

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

**Layer view only**

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

**File tree view only**

| Key | Action |
|---|---|
| <kbd>Space</kbd> | Collapse / uncollapse the selected directory |
| <kbd>Ctrl</kbd>+<kbd>Space</kbd> | Collapse / uncollapse all directories |
| <kbd>Ctrl</kbd>+<kbd>A</kbd> | Show / hide added files |
| <kbd>Ctrl</kbd>+<kbd>R</kbd> | Show / hide removed files |
| <kbd>Ctrl</kbd>+<kbd>M</kbd> | Show / hide modified files |
| <kbd>Ctrl</kbd>+<kbd>U</kbd> | Show / hide unmodified files |
| <kbd>Ctrl</kbd>+<kbd>B</kbd> | 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:

```bash
# 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:

```bash
dive config
```

### 7.2 Display preferences

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

```yaml
# 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.

```yaml
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:

```bash
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`):

```yaml
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
```

```bash
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

```bash
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**

```bash
dive my-app:latest
```
Read the efficiency report pane. Then in the file tree, press <kbd>Ctrl</kbd>+<kbd>U</kbd> to hide unmodified files and <kbd>Ctrl</kbd>+<kbd>A</kbd> in the layer view to see aggregated changes — duplicated/removed files stand out.

**Gate a build in CI on image efficiency**

```bash
# .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)**

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

**Capture results for later or for another tool**

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

**Hide the noise and focus on what each layer added**

```yaml
# ~/.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](#42-choosing-where-the-image-comes-from).

### 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:
```bash
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:
```bash
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) |

---

_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. Unofficial; not affiliated with or reviewed by the project._
