# Dive Filetree Package: Core Engine for Docker Image Layer Analysis and Visualization

> Explore the dive/filetree package, Docker image layer analysis’s core engine. Model, compare, and visualize layer filesystems for interactive ASCII tree analysis.

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

---

**The `dive/filetree` package provides the core data structures and algorithms for modeling, comparing, stacking, and rendering hierarchical filesystem views of Docker image layers, enabling the interactive ASCII tree visualization in the Dive CLI tool.**

The `dive/filetree` package in the `wagoodman/dive` repository serves as the foundational engine for analyzing container image layers. It handles everything from parsing tar headers to generating the interactive file tree displayed in the terminal. Whether you are building a Docker image analyzer or need to programmatically compare filesystem states, this package offers robust primitives for **tree construction**, **layer stacking**, and **diff visualization**.

## Core Functionalities of the Dive Filetree Package

### Hierarchical File Tree Modeling

At the heart of the package are the `FileTree` and `FileNode` structs defined in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go) and [`dive/filetree/file_node.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_node.go). A `FileTree` represents a complete filesystem snapshot as a tree of `FileNode` instances, where each node holds metadata via `FileInfo` and UI state via `ViewInfo`.

The `FileInfo` struct, implemented in [`dive/filetree/file_info.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_info.go), captures essential file attributes extracted from tar headers, including path, size, permissions, and content hashes. The function `NewFileInfoFromTarHeader` parses tar archive headers to populate these fields, enabling accurate filesystem representation from Docker image layers.

### Layer Stacking and Overlay Filesystem Support

The package implements Docker's overlay filesystem semantics through the `Stack` method in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go). This functionality merges an upper layer onto a lower layer, handling white-out files (`.wh.`) that indicate deletions in Docker overlay storage.

When stacking, the algorithm walks the upper tree and applies changes to the lower tree: deleting paths marked by white-out files and adding or replacing other entries. This produces a cumulative view of the filesystem as it would appear after applying multiple image layers, which is essential for analyzing image efficiency and bloat.

### Diff Calculation and Change Detection

The `CompareAndMark` method in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go) enables precise comparison between two file trees, marking each node with a `DiffType` indicating whether it was **Added**, **Removed**, **Modified**, or left **Unmodified**.

The comparison algorithm walks the new (upper) tree and compares each node against its counterpart in the reference tree using the `compare` function. Results are stored in `FileNode.Data.DiffType`, with parent nodes inheriting status from children through `deriveDiffType`. This diff engine powers Dive's ability to highlight exactly which files changed between image layers.

### Tree Traversal and Sorting Strategies

The package provides flexible traversal utilities through `VisitDepthChildFirst` and `VisitDepthParentFirst` in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go). These depth-first visitors support optional evaluator functions for filtering nodes during traversal, enabling efficient searches and transformations.

Sorting behavior is controlled through the `OrderStrategy` interface implemented in [`dive/filetree/order_strategy.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/order_strategy.go). The package offers two built-in strategies: `orderByNameStrategy` for alphabetical ordering and `orderBySizeDescStrategy` for descending size sorting. The `FileTree.SortOrder` field selects the active strategy, which the rendering engine uses when displaying child nodes.

### ASCII Rendering and View State Management

The rendering pipeline in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go) generates human-readable ASCII tree representations through `renderStringTreeBetween`, `String`, and `StringBetween` methods. These functions produce branch graphics (`├─`, `└─`, etc.) and optional metadata columns for terminal display.

Each `FileNode` maintains UI state through the `ViewInfo` struct defined in [`dive/filetree/view_info.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/view_info.go), tracking whether nodes are `Collapsed` or `Hidden`. This separation of model and view concerns allows the package to support interactive features like directory collapsing and filtered views without mutating the underlying filesystem data.

### Cached Layer Comparison

The `Comparer` type in [`dive/filetree/comparer.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/comparer.go) provides high-level caching for multi-layer analysis. It generates and caches combined trees for arbitrary layer ranges, exposing `GetTree` for retrieving cumulative views and `GetPathErrors` for accessing processing errors.

This cache layer optimizes performance when navigating between different image layers in the UI, avoiding redundant restacking operations. The `Comparer` coordinates the `Stack` and `CompareAndMark` operations to present a consistent, navigable view of the image's layer history.

## Working with the Filetree Package: Code Examples

### Creating a File Tree from Paths

The following example demonstrates constructing a `FileTree` programmatically using the `AddPath` method:

```go
import (
    "github.com/wagoodman/dive/dive/filetree"
)

func buildDemoTree() *filetree.FileTree {
    tree := filetree.NewFileTree()
    // Simulate three files
    tree.AddPath("/etc/hosts", filetree.FileInfo{Path: "/etc/hosts", IsDir: false, Size: 1024})
    tree.AddPath("/usr/bin/bash", filetree.FileInfo{Path: "/usr/bin/bash", IsDir: false, Size: 123456})
    tree.AddPath("/var/log", filetree.FileInfo{Path: "/var/log", IsDir: true})
    return tree
}

```

This example utilizes `NewFileTree` defined in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go) and the `AddPath` method to populate the tree structure with `FileInfo` metadata.

### Stacking Layers and Calculating Diffs

To analyze Docker image layers, you can stack an upper layer onto a lower layer and compute differences:

```go
// lower and upper are *filetree.FileTree built from separate image layers
lower := buildDemoTree()
upper := filetree.NewFileTree()
upper.AddPath("/etc/hosts", filetree.FileInfo{Path: "/etc/hosts", IsDir: false, Size: 2048}) // modified size
upper.AddPath("/usr/bin/ls", filetree.FileInfo{Path: "/usr/bin/ls", IsDir: false, Size: 54321}) // added file
// Simulate a white‑out (deletion) of /var/log
upper.AddPath("/var/log/.wh..wh..", filetree.FileInfo{Path: "/var/log/.wh..wh..", IsDir: false})

stacked, _, _ := lower.Stack(upper) // `Stack` handles white‑outs
_ = stacked.CompareAndMark(upper)   // annotate diff types
fmt.Println(stacked.String(true))   // render with attributes

```

The `Stack` method in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go) handles Docker overlay white-out files, while `CompareAndMark` annotates each node with `DiffType` indicators showing whether files were added, removed, or modified.

### Rendering Interactive Views

For UI applications, the package supports view models that handle collapsing and paging:

```go
vm, _ := viewmodel.NewFileTreeViewModel(cfg, 0) // cfg supplies the comparer and trees
vm.Setup(0, 20)                               // visible height = 20 lines
vm.ToggleCollapseAll()                        // collapse everything
_ = vm.Update(nil, 80, 20)                    // no regex filter, width 80
_ = vm.Render()
fmt.Println(vm.Buffer.String())

```

This example demonstrates integration with the view model defined in [`cmd/dive/cli/internal/ui/v1/viewmodel/filetree.go`](https://github.com/wagoodman/dive/blob/main/cmd/dive/cli/internal/ui/v1/viewmodel/filetree.go), which wraps the core `dive/filetree` types to provide interactive features like directory collapsing and filtered views.

## Key Source Files in the dive/filetree Package

Understanding the package structure requires familiarity with these core files:

- **[`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go)** — Contains the `FileTree` struct and core methods including `AddPath`, `Stack`, `CompareAndMark`, and rendering functions like `String` and `renderStringTreeBetween`.

- **[`dive/filetree/file_node.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_node.go)** — Defines the `FileNode` struct representing individual files or directories, including metadata formatting and size aggregation logic.

- **[`dive/filetree/file_info.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_info.go)** — Implements `FileInfo` for tar header parsing via `NewFileInfoFromTarHeader` and content hash generation.

- **[`dive/filetree/diff.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/diff.go)** — Defines the `DiffType` enumeration (Added, Removed, Modified, Unmodified) used for marking changes between trees.

- **[`dive/filetree/view_info.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/view_info.go)** — Provides `ViewInfo` for UI state management, tracking `Collapsed` and `Hidden` flags per node.

- **[`dive/filetree/comparer.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/comparer.go)** — Implements the `Comparer` type with caching logic for multi-layer tree composition via `GetTree` and `GetPathErrors`.

- **[`dive/filetree/order_strategy.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/order_strategy.go)** — Contains sorting strategies including `orderByNameStrategy` and `orderBySizeDescStrategy` for controlling node traversal order.

- **[`cmd/dive/cli/internal/ui/v1/viewmodel/filetree.go`](https://github.com/wagoodman/dive/blob/main/cmd/dive/cli/internal/ui/v1/viewmodel/filetree.go)** — Wraps the core package for interactive UI use, handling view updates, collapsing, and rendering buffers.

## Summary

The `dive/filetree` package delivers a complete toolkit for Docker image filesystem analysis:

- **Tree Modeling** — Represents filesystems as hierarchical `FileNode` structures with `FileInfo` metadata extracted from tar headers.
- **Layer Operations** — Stacks Docker image layers using overlay filesystem semantics, handling white-out deletions via the `Stack` method.
- **Diff Engine** — Calculates precise changes between layers using `CompareAndMark`, categorizing nodes as Added, Removed, Modified, or Unmodified.
- **Rendering System** — Generates ASCII tree visualizations with branch graphics and metadata columns through `String` and `renderStringTreeBetween`.
- **UI Integration** — Supports interactive features like collapsing and filtering via `ViewInfo` and the `Comparer` cache for efficient layer navigation.

## Frequently Asked Questions

### How does the dive/filetree package handle Docker overlay white-out files?

The package recognizes white-out files (prefixed with `.wh.`) through the `Stack` method in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go). When stacking an upper layer onto a lower layer, the algorithm detects these special markers and removes the corresponding paths from the resulting tree, accurately simulating how Docker's overlay filesystem handles file deletions across layers.

### What is the difference between FileTree and FileNode in the dive/filetree package?

`FileTree` acts as the container and manager for the entire filesystem representation, providing methods like `AddPath`, `Stack`, and `CompareAndMark` in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go). `FileNode` represents individual files or directories within that tree, storing metadata via `FileInfo` and UI state via `ViewInfo` in [`dive/filetree/file_node.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_node.go). While `FileTree` handles operations on the whole structure, `FileNode` maintains the hierarchical relationships and individual attributes.

### How does the CompareAndMark method determine file modifications?

The `CompareAndMark` method in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go) walks the upper (newer) tree and compares each node against its counterpart in the reference tree using the `compare` function. It examines `FileInfo` attributes such as size, permissions, and content hashes to detect changes. The method then marks each node with a `DiffType`—Added, Removed, Modified, or Unmodified—and propagates these statuses upward through parent nodes via `deriveDiffType` to indicate aggregate changes in directories.

### Can the dive/filetree package be used independently of the Dive CLI?

Yes, the `dive/filetree` package functions as a standalone library for filesystem tree manipulation and comparison. You can import `github.com/wagoodman/dive/dive/filetree` to build trees programmatically using `NewFileTree` and `AddPath`, stack layers with `Stack`, and generate ASCII representations with `String`. While the package includes UI-specific types like `ViewInfo` and integrates with the `Comparer` cache for layer navigation, these components are optional when using the core tree modeling and diffing capabilities for custom applications.