# How Dive Handles Docker and Podman Container Runtimes

> Discover how Dive seamlessly supports Docker and Podman container runtimes. Learn about its abstraction layer and automatic selection for efficient image analysis.

- Repository: [Alex Goodman/dive](https://github.com/wagoodman/dive)
- Tags: internals
- Published: 2026-03-07

---

**Dive abstracts container runtime differences behind the `image.Resolver` interface, automatically selecting Docker Engine, Podman, or archive resolvers at runtime based on the `--source` flag.**

Dive, the popular container image exploration tool by wagoodman/dive, supports multiple container runtimes through a clean abstraction layer. Rather than hardcoding Docker-specific logic, the tool implements a strategy pattern using the `image.Resolver` interface. This design allows seamless analysis of images from Docker Engine, Podman, or local archives without modifying the core analysis engine.

## The Resolver Interface Architecture

The architecture centers on the `image.Resolver` interface, which standardizes how Dive obtains, builds, or extracts container images. Each supported runtime implements this interface differently, but all implementations ultimately produce a Docker-compatible image archive for the analysis pipeline. This convergence ensures that layer analysis and filesystem exploration work identically regardless of the source.

## Docker Engine Support

Dive communicates with Docker through the `docker.engineResolver` type defined in [`dive/image/docker/engine_resolver.go`](https://github.com/wagoodman/dive/blob/main/dive/image/docker/engine_resolver.go). This implementation uses the official Docker Go SDK to communicate with the daemon.

When fetching an image, the resolver first checks local storage and automatically pulls missing images. It then streams the image archive using `dockerClient.ImageSave` and passes the stream to `docker.NewImageArchive` for parsing. The constructor `NewResolverFromEngine` and the `fetchArchive` method (lines 63-71) handle this orchestration.

## Podman Engine Support

Podman support is implemented in [`dive/image/podman/resolver.go`](https://github.com/wagoodman/dive/blob/main/dive/image/podman/resolver.go) via the `podman.resolver` type. Rather than using a Podman-specific SDK, this resolver acts as a thin wrapper around the existing Docker archive infrastructure.

The resolver shells out to the Podman CLI, executing `podman image save` to generate a Docker-compatible tarball. It then passes this archive to `docker.NewImageArchive`, reusing the standard parsing logic. This approach works on Linux and macOS where the Podman CLI is available. The `resolveFromDockerArchive` and `Extract` functions (lines 59-70) manage this translation layer.

## Docker Archive Support

For existing image archives, Dive provides `docker.archiveResolver` (created via `NewResolverFromArchive`). This resolver reads local tar or zip files containing Docker image archives without requiring a running daemon, using the same parsing pipeline as the engine-based resolvers.

## Runtime Selection Logic

The selection mechanism resides in [`dive/get_image_resolver.go`](https://github.com/wagoodman/dive/blob/main/dive/get_image_resolver.go). The CLI flag `--source` maps to an `ImageSource` enum (`SourceDockerEngine`, `SourcePodmanEngine`, or `SourceDockerArchive`), which the `GetImageResolver` function uses to instantiate the correct implementation:

```go
func GetImageResolver(r ImageSource) (image.Resolver, error) {
    switch r {
    case SourceDockerEngine:
        return docker.NewResolverFromEngine(), nil
    case SourcePodmanEngine:
        return podman.NewResolverFromEngine(), nil
    case SourceDockerArchive:
        return docker.NewResolverFromArchive(), nil
    }
    return nil, fmt.Errorf("unable to determine image resolver")
}

```

This switch statement (lines 62-73) is invoked from the CLI entry point in [`cmd/dive/cli/internal/command/root.go`](https://github.com/wagoodman/dive/blob/main/cmd/dive/cli/internal/command/root.go) (line 46). The fetched resolver is then passed to `adapter.ImageResolver(resolver).Fetch(ctx, opts.Analysis.Image)` to retrieve the image for analysis.

## Practical Usage Examples

Select your container runtime using the `--source` flag:

```bash

# Default: Analyze from local Docker daemon

dive nginx:latest

# Analyze from Podman

dive --source=podman myapp:latest

# Analyze local tarball

dive --source=docker-archive ./myimage.tar

```

Integrate Dive's runtime selection programmatically in Go:

```go
package main

import (
    "context"
    "log"

    "github.com/wagoodman/dive"
    "github.com/wagoodman/dive/dive/image"
)

func main() {
    // Select runtime source
    src := dive.SourcePodmanEngine // or SourceDockerEngine, SourceDockerArchive
    
    resolver, err := dive.GetImageResolver(src)
    if err != nil {
        log.Fatalf("resolver error: %v", err)
    }
    
    img, err := resolver.Fetch(context.Background(), "myimage:latest")
    if err != nil {
        log.Fatalf("fetch error: %v", err)
    }
    
    // Image ready for analysis
    _ = img
}

```

## Summary

- **Abstracted Interface**: Dive uses the `image.Resolver` interface to decouple image fetching from analysis logic, located in [`dive/get_image_resolver.go`](https://github.com/wagoodman/dive/blob/main/dive/get_image_resolver.go).
- **Docker Integration**: The `docker.engineResolver` uses the Docker Go SDK and `ImageSave` API to stream images directly from the daemon via [`dive/image/docker/engine_resolver.go`](https://github.com/wagoodman/dive/blob/main/dive/image/docker/engine_resolver.go).
- **Podman Compatibility**: The `podman.resolver` shells out to `podman image save` and reuses Docker archive parsing in [`dive/image/podman/resolver.go`](https://github.com/wagoodman/dive/blob/main/dive/image/podman/resolver.go), avoiding Podman-specific complexity.
- **Unified Pipeline**: All resolvers ultimately produce Docker-compatible archives processed by `docker.NewImageArchive`, ensuring consistent analysis regardless of source.
- **User Control**: The `--source` flag maps to the `ImageSource` enum to select resolvers at runtime without code changes.

## Frequently Asked Questions

### Can Dive analyze images from containerd or CRI-O?

Dive does not currently implement native resolvers for containerd or CRI-O. However, if these runtimes can export Docker-compatible image archives using tools like `ctr image export`, you can analyze them using the `--source=docker-archive` flag.

### Why does the Podman resolver use Docker's archive parser instead of a native implementation?

According to the source code in [`dive/image/podman/resolver.go`](https://github.com/wagoodman/dive/blob/main/dive/image/podman/resolver.go), the Podman resolver intentionally wraps the Docker archive parser because Podman's `image save` command produces Docker-compatible tarballs. This reuse avoids duplicating parsing logic and ensures feature parity between runtime sources while minimizing maintenance overhead.

### Does Dive require the Docker daemon to be running when using Podman?

No, when using `--source=podman`, Dive only requires the Podman CLI to be installed and accessible in the system path. It does not communicate with or require a running Docker daemon, as it shells out to `podman image save` directly and processes the resulting archive independently.

### How does Dive handle image pulling for Docker versus Podman?

The Docker resolver automatically pulls missing images via the Docker SDK before exporting them through `ImageSave`. The Podman resolver relies on Podman's native behavior when executing `podman image save`, which will pull the image if it doesn't exist locally depending on the Podman configuration and version.