# FileTree Struct in Dive: How Container Filesystems Are Modeled and Analyzed

> Explore Dive's FileTree struct, the central in-memory model for container filesystems. Understand how it represents hierarchy, stores metadata, and enables analysis of layer diffs.

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

---

**The `FileTree` struct in Dive is the core in-memory representation of a container image's filesystem hierarchy, storing the root node, visible node count, total file size, and metadata required to render ASCII trees and compute layer diffs.**

The `FileTree` struct serves as the foundational data structure in the [wagoodman/dive](https://github.com/wagoodman/dive) source code that enables deep analysis of Docker and OCI container images. Defined in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go), this struct models the complete set of files, directories, and their relationships within a single image layer or an entire image filesystem, powering Dive's terminal UI and efficient diff calculations.

## What Is the FileTree Struct in Dive?

The `FileTree` struct acts as the primary in-memory model that captures the hierarchy of files and directories existing inside a container image or a single image layer. It abstracts complex filesystem metadata into a traversable tree structure that Dive uses to visualize layer contents, calculate space utilization, and identify changes between image layers.

### Core Purpose and Capabilities

According to the Dive source code, the `FileTree` struct enables three critical functions:

- **Filesystem Modeling**: Stores the complete directory structure and file metadata for a given layer, including paths, sizes, and permissions
- **Diff Computation**: Compares two `FileTree` instances to identify added, removed, or modified files between layers using the `CompareAndMark` method
- **UI Rendering**: Generates ASCII tree visualizations showing file paths, sizes, and change markers in the terminal interface via the `String` method

## FileTree Struct Definition and Fields

The struct definition resides in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go) at lines 24-32:

```go
// FileTree represents a set of files, directories, and their relations.
type FileTree struct {
    Root      *FileNode   // top‑level node (virtual root)
    Size      int         // number of visible nodes (excluding root)
    FileSize  uint64      // total byte size of all files in the tree
    Name      string      // optional name/label for the tree (e.g., layer digest)
    Id        uuid.UUID   // unique identifier for the tree instance
    SortOrder SortOrder   // how children are ordered when traversed/rendered
}

```

Each field serves a specific purpose in the container image analysis workflow:

- **`Root`** (`*FileNode`): Anchors the entire tree structure with a virtual root node that contains all top-level directories and files as defined in [`dive/filetree/file_node.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_node.go)
- **`Size`** (`int`): Tracks the count of visible nodes excluding the artificial root, used for UI statistics and pagination
- **`FileSize`** (`uint64`): Accumulates the total byte size of all files in the tree, enabling accurate layer size calculations and space analysis
- **`Name`** (`string`): Provides a human-readable identifier, typically populated with the layer digest or image reference for debugging
- **`Id`** (`uuid.UUID`): Assigns a unique identifier to each tree instance for cache management and comparison operations
- **`SortOrder`** (`SortOrder`): Defines the traversal strategy (by name, size, etc.) used when rendering the tree in the terminal UI

## Working with the FileTree Struct in Go

The `dive/filetree` package provides methods to construct, manipulate, and compare `FileTree` instances. These operations form the backbone of Dive's image analysis capabilities.

### 1. Creating a New FileTree

Initialize an empty tree and assign identifying metadata:

```go
tree := filetree.NewFileTree()
tree.Name = "layer-1"

```

### 2. Adding File Paths

Populate the tree with file metadata using absolute paths:

```go
info := filetree.FileInfo{
    Path:   "usr/bin/app",
    Size:   123456,
    Mode:   0755,
    IsDir:  false,
}
node, _, err := tree.AddPath("/usr/bin/app", info)
if err != nil { 
    // handle error 
}

```

### 3. Retrieving Nodes

Access specific files or directories by their absolute path:

```go
node, err := tree.GetNode("/usr/bin/app")
if err != nil { 
    // not found 
}
fmt.Println("File size:", node.Data.FileInfo.Size)

```

### 4. Rendering the ASCII Tree

Generate human-readable output for the terminal UI:

```go
fmt.Println(tree.String(true)) // `true` adds file attributes (size, mode, etc.)

```

### 5. Comparing Trees for Layer Diffs

Compute differences between two `FileTree` instances to identify filesystem changes:

```go
lower := filetree.NewFileTree()
// …populate lower…
upper := filetree.NewFileTree()
// …populate upper…

if _, err := lower.CompareAndMark(upper); err != nil {
    // diff annotations (Added, Removed, Modified) are now attached to nodes
}

```

The `CompareAndMark` method, as implemented in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go), traverses both trees simultaneously and annotates nodes with change types that the UI renders as color-coded indicators.

## Key Source Files in the FileTree Architecture

Understanding the `FileTree` struct requires familiarity with several interconnected components in the wagoodman/dive repository:

- **[`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go)**: Contains the `FileTree` struct definition and core operations including `NewFileTree`, `AddPath`, `GetNode`, `CompareAndMark`, and tree traversal logic
- **[`dive/filetree/file_node.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_node.go)**: Defines `FileNode`, the individual file/directory representation that comprises the tree nodes, along with rendering helpers for the ASCII output
- **[`dive/filetree/file_tree_test.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree_test.go)**: Provides unit tests exercising tree creation, manipulation, copying, and edge cases to ensure correctness
- **[`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)**: Implements the UI view-model that wraps `FileTree` for the right-pane display in the terminal interface
- **[`dive/filetree/comparer.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/comparer.go)**: Houses higher-level diff logic that orchestrates `FileTree.CompareAndMark` to produce comprehensive layer comparisons

These components work together to model, analyze, and visualize the filesystem structure of Docker and OCI images layer by layer.

## Summary

- The `FileTree` struct in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go) is the central data structure for modeling container image filesystems in Dive
- It tracks the root node, visible node count, total file size, and traversal ordering via the `Root`, `Size`, `FileSize`, and `SortOrder` fields
- The struct supports filesystem construction through `AddPath`, node retrieval via `GetNode`, and ASCII rendering with `String()`
- Layer diffs are computed using `CompareAndMark`, which annotates nodes with change states (Added, Removed, Modified)
- The architecture separates tree logic ([`file_tree.go`](https://github.com/wagoodman/dive/blob/main/file_tree.go)), node representation ([`file_node.go`](https://github.com/wagoodman/dive/blob/main/file_node.go)), UI presentation ([`viewmodel/filetree.go`](https://github.com/wagoodman/dive/blob/main/viewmodel/filetree.go)), and comparison orchestration ([`comparer.go`](https://github.com/wagoodman/dive/blob/main/comparer.go))

## Frequently Asked Questions

### What does the FileTree struct represent in Dive?

The `FileTree` struct represents the complete hierarchy of files and directories within a container image layer or an entire image filesystem. It serves as the in-memory model that Dive uses to track file metadata, compute space utilization, and render the ASCII tree view in the terminal UI.

### Where is the FileTree struct defined in the Dive source code?

The `FileTree` struct is defined in [`dive/filetree/file_tree.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_tree.go) at lines 24-32. This file also contains the primary methods for tree manipulation including `NewFileTree`, `AddPath`, `GetNode`, `CompareAndMark`, and the `String` method for ASCII rendering.

### How does Dive use the FileTree struct to show layer differences?

Dive uses the `CompareAndMark` method to compare two `FileTree` instances representing different layers. This method traverses both trees simultaneously, identifying nodes that exist only in the upper tree (Added), only in the lower tree (Removed), or with differing metadata (Modified). These annotations are then rendered as color-coded indicators in the terminal UI by the view-model 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).

### What is the difference between FileTree and FileNode in Dive?

`FileTree` is the container struct that holds the entire filesystem model including the root node and aggregate statistics like total size. `FileNode`, defined in [`dive/filetree/file_node.go`](https://github.com/wagoodman/dive/blob/main/dive/filetree/file_node.go), represents individual files or directories within that tree. Each `FileTree` has a `Root` field pointing to a `FileNode`, which then links to child nodes via pointer relationships to form the complete directory hierarchy.