# Understanding the fzf Walker Option: Built-in File Traversal Guide

> Learn how the fzf walker option enables built-in file traversal for efficient command-line fuzzy finding. Explore its purpose and file generation.

- Repository: [Junegunn Choi/fzf](https://github.com/junegunn/fzf)
- Tags: deep-dive
- Published: 2026-03-01

---

**The `--walker` option in `fzf` configures the built-in directory walker that generates candidate lists when no input is provided via STDIN or `FZF_DEFAULT_COMMAND`.**

When you launch `junegunn/fzf` without piped input, it relies on an internal file traversal system to populate the interactive finder. The `--walker` family of options gives you fine-grained control over this process, allowing you to specify entry types, root directories, and skip patterns without writing custom shell commands.

## What Is the fzf Walker Option?

The `fzf` walker is controlled by three command-line flags that determine how the file system is scanned:

- **`--walker=OPTS`** – A comma-separated list of filters: `file`, `dir`, `hidden`, and `follow`. By default, `fzf` uses `file,follow,hidden`, meaning it lists files (not directories), follows symbolic links, and includes hidden entries.
- **`--walker-root=DIR …`** – One or more root directories where traversal begins (default: `.`).
- **`--walker-skip=DIRS`** – Comma-separated directory names to exclude (e.g., `.git,node_modules,target`).

These options are defined and parsed in [`src/options.go`](https://github.com/junegunn/fzf/blob/main/src/options.go), where the `walkerOpts` struct stores the boolean flags for each filter type.

## How the fzf Walker Traverses Files

The traversal logic is implemented in [`src/reader.go`](https://github.com/junegunn/fzf/blob/main/src/reader.go) and leverages the high-performance `fastwalk` library for cross-platform efficiency. The process unfolds in three stages:

### Parsing Walker Options

When `fzf` starts, `parseWalkerOpts` in [`src/options.go`](https://github.com/junegunn/fzf/blob/main/src/options.go) (lines 1587–1608) converts the comma-separated string into a structured `walkerOpts` value:

```go
func parseWalkerOpts(str string) (walkerOpts, error) {
    opts := walkerOpts{}
    for _, str := range strings.Split(strings.ToLower(str), ",") {
        switch str {
        case "file":   opts.file = true
        case "dir":    opts.dir = true
        case "hidden": opts.hidden = true
        case "follow": opts.follow = true
        // ...
        }
    }
    return opts, nil
}

```

### The File Walking Implementation

The core traversal occurs in `readFiles` ([`src/reader.go`](https://github.com/junegunn/fzf/blob/main/src/reader.go), lines 270–332). This function configures `fastwalk` with the `follow` setting from `--walker` and defines a callback that filters each path:

```go
func (r *Reader) readFiles(roots []string, opts walkerOpts, ignores []string) bool {
    conf := fastwalk.Config{
        Follow: opts.follow,
        ToSlash: fastwalk.DefaultToSlash(),
        Sort:    fastwalk.SortFilesFirst,
    }
    // ...
    fn := func(path string, de os.DirEntry, err error) error {
        path = trimPath(path)
        // Filtering logic applied here...
        return nil
    }
    for _, root := range roots {
        fastwalk.Walk(&conf, root, fn)
    }
    return noerr
}

```

### Filtering and Entry Types

The callback function inside `readFiles` enforces the `--walker` constraints:

- **Hidden files** are skipped unless `opts.hidden` is true, checked by inspecting if the base name starts with a dot.
- **Skip patterns** from `--walker-skip` are matched against base names, full paths, and suffixes using `slices.Contains`.
- **Entry types** are distinguished using `de.IsDir()`. When `opts.dir` is true, a trailing slash is appended to directory paths before they are pushed to the candidate list.
- **Symlinks** are resolved according to the `fastwalk.Config.Follow` boolean set by `--walker=follow`.

Only entries matching the requested type (`file` or `dir`) are passed to `r.pusher`, which streams them into `fzf`’s internal event loop for interactive filtering.

## Practical Examples of the fzf Walker Option

These commands demonstrate how to leverage the built-in walker without external tools like `find`:

```bash

# List all files, directories, hidden entries, and follow symlinks

fzf --walker=file,dir,hidden,follow

# Skip version-control and dependency folders

fzf --walker-skip=.git,node_modules,target

# Walk two separate trees (e.g., source and libraries)

fzf --walker-root=src,lib --walker=file,dir,hidden

# Only list directories (useful for selecting a folder)

fzf --walker=dir,hidden

```

Because the walker runs internally, these invocations work even when no input is piped into `fzf`, providing a consistent experience across macOS, Linux, and Windows.

## Summary

- The **`--walker`** option configures `fzf`’s built-in directory traversal engine, which activates when STDIN and `FZF_DEFAULT_COMMAND` are absent.
- It supports filtering by **entry type** (`file`, `dir`), **visibility** (`hidden`), and **symlink resolution** (`follow`), parsed by `parseWalkerOpts` in [`src/options.go`](https://github.com/junegunn/fzf/blob/main/src/options.go).
- The actual traversal is handled by `readFiles` in [`src/reader.go`](https://github.com/junegunn/fzf/blob/main/src/reader.go) using the **fastwalk** library for high-performance, cross-platform file walking.
- Users can define **multiple root directories** with `--walker-root` and **exclude patterns** with `--walker-skip`, making the built-in walker a flexible alternative to external `find` commands.

## Frequently Asked Questions

### What is the default behavior of the fzf walker option?

By default, `fzf` uses `--walker=file,follow,hidden`, which means it lists files (not directories), follows symbolic links, and includes hidden files. This default is defined in the option parsing logic within [`src/options.go`](https://github.com/junegunn/fzf/blob/main/src/options.go) and ensures that `fzf` behaves like a standard file finder when launched without arguments.

### How does fzf handle symbolic links when using the walker?

Symbolic link handling is controlled by the `follow` flag in the `--walker` option. When `follow` is specified, `fzf` sets `fastwalk.Config.Follow` to `true` in [`src/reader.go`](https://github.com/junegunn/fzf/blob/main/src/reader.go), causing the walker to traverse into directories pointed to by symlinks. Without this flag, symbolic links are listed but not followed into, preventing infinite loops and unexpected directory traversal.

### Can I use multiple root directories with the fzf walker?

Yes, the `--walker-root` option accepts one or more directory paths. In [`src/reader.go`](https://github.com/junegunn/fzf/blob/main/src/reader.go), the `readFiles` function iterates over the slice of root directories provided, running `fastwalk.Walk` on each. This allows you to search across disparate locations—such as `src` and `lib` directories—simultaneously within a single `fzf` instance.

### Why does fzf skip certain directories like .git by default?

While `fzf` does not hardcode specific directories to skip, it provides the `--walker-skip` option specifically for this purpose. Users commonly set this to `.git,node_modules,target` to exclude version control and build artifact directories. The filtering occurs in the `readFiles` callback in [`src/reader.go`](https://github.com/junegunn/fzf/blob/main/src/reader.go), where the walker checks the provided ignore list against base names and full paths before emitting a candidate.