Skip to main content

fzf Philosophy and Design

fzf's power comes from its philosophy: do one thing, do it interactively, and compose with everything else. Understanding this design principle makes you a far more effective fzf user.

The Unix Filter Model​

Unix tools are built around the idea of small, composable programs connected by pipes. fzf is a perfect Unix citizen:

STDIN → fzf (interactive select) → STDOUT

It has no opinion about:

  • What data it receives (files, processes, commits, URLs — anything)
  • What the caller does with the output (open, delete, copy, pipe further)
  • What shell or editor you use

This is intentional. By staying minimal, fzf works everywhere.

"Interactive" vs "Batch" Filtering​

ModeToolUse case
Batchgrep, awk, sedYou know the pattern; automate it
InteractivefzfYou need to see the options and choose
# Batch: you know exactly what you want
grep "ERROR" /var/log/syslog | tail -20

# Interactive: you want to browse and pick
grep "ERROR" /var/log/syslog | fzf --preview 'echo {}' --preview-window=down:3

The Three Rules of fzf Design​

Rule 1: Accept Any Line-Based Input​

fzf does not care if the input is filenames, log lines, JSON, git SHAs, IP addresses, or hostnames. It treats everything as opaque text lines and lets you filter them.

# Works with any list:
cat /etc/passwd | fzf # users
docker images | fzf # images
kubectl get pods | fzf # pods
history | fzf # commands
curl -s 'https://api.github.com/repos/torvalds/linux/commits' \
| jq -r '.[].commit.message' | fzf # commit messages

Rule 2: Output is Consumable by Other Tools​

fzf outputs what you select to stdout. The consuming command decides what to do with it:

# Select, then open
fzf | xargs nvim

# Select, then delete
find . -name "*.tmp" | fzf -m | xargs rm

# Select, then copy to clipboard
ls | fzf | xclip -selection clipboard

Rule 3: Behavior is Composable via Flags​

fzf's extensive --flag system lets you compose complex behaviors at the call site, not inside fzf itself:

fzf \
--multi \ # allow multiple selections
--preview 'bat --color=always {}' \ # preview command
--preview-window 'right:60%' \ # preview layout
--bind 'ctrl-/:toggle-preview' \ # custom keybinding
--header 'Select files to edit' \ # status header
--prompt 'Files> ' \ # custom prompt
--pointer '▶' \ # selection pointer
--marker '✓' # multi-select marker

What fzf Deliberately Omits​

FeatureWhy fzf omits it
Built-in file browserUse find, fd, or ls as input — more flexible
Config fileUse FZF_DEFAULT_OPTS env variable — scriptable
Plugin systemUse shell functions — composable with existing tools
State persistenceUse the shell's history and aliases
GUI versionIt's a TUI tool — intentionally terminal-native

The Mental Model: "Interactive xargs"​

If you know xargs, you can think of fzf as interactive xargs:

# xargs: non-interactive, process all matching items
find . -name "*.log" | xargs grep "ERROR"

# fzf + xargs: interactive, YOU pick which log to grep
find . -name "*.log" | fzf | xargs grep "ERROR"

Composability in Practice​

Next Steps​