TL;DR:
- fzf is a fast, general-purpose fuzzy finder for the terminal — select items interactively from any list, pipe anything into it
- The built-in shell integrations for history search (
Ctrl+R), file completion (Ctrl+T), and directory navigation (Alt+C) alone justify installing it - Combine with ripgrep, bat, and git for a dramatically faster file-searching and branch-switching workflow
fzf has been around since 2014 and it’s still the kind of tool that people discover and immediately install on every machine they use. The concept is simple: it takes any list of items, lets you fuzzy-search them in real time, and returns your selection to stdout. That’s it. The power comes from plugging that pattern into dozens of different workflows.
Installing fzf
# macOS
brew install fzf
$(brew --prefix)/opt/fzf/install
# Ubuntu/Debian
sudo apt install fzf
# Arch
sudo pacman -S fzf
# Any platform — via git
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install
Run the install script after installing — it adds the shell integrations that provide most of the immediate value. Say yes to all three prompts (history, file completion, and directory navigation).
The Shell Integrations You’ll Use Every Day
Ctrl+R — Fuzzy shell history search. This replaces the standard reverse-history search. Start typing any part of a command you ran before — not necessarily the beginning — and fzf fuzzy-matches against your entire shell history and shows the results in a scrollable list. Select an entry and it drops into your command line for editing before you run it.
This is the single biggest productivity upgrade fzf provides for most people. If you’ve ever known you ran a complex curl or docker command a week ago and spent a minute pressing Ctrl+R repeatedly to find it, this replaces that with an instant interactive search.
Ctrl+T — File and directory completion. When you’re mid-command, Ctrl+T opens a fuzzy file picker rooted at the current directory. Start typing a filename or directory name, navigate to the file, and press Enter to insert the path into your command. Useful for any command where you’d otherwise need to remember or type a full path.
Alt+C — cd to any directory. Opens a fuzzy picker of directories in the current tree. Select one and you’re immediately in it. Combine with fd instead of the default find for faster directory listing.
File Search with Preview
The default fzf experience is functional, but a common upgrade is adding file previews using bat (a cat clone with syntax highlighting):
# Add to your .bashrc or .zshrc
export FZF_DEFAULT_OPTS='--height 60% --border --preview "bat --color=always {} 2>/dev/null || cat {}"'
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
With fd as the default command, fzf searches files faster (fd is built in Rust and ignores .gitignore entries by default) and the bat preview shows you the file content with syntax highlighting before you select it.
Open any file directly:
# Open selected file in $EDITOR
vim $(fzf)
# Or as a function in your .bashrc/.zshrc
fv() {
local file
file=$(fzf --preview 'bat --color=always {}')
[ -n "$file" ] && ${EDITOR:-vim} "$file"
}
Git Branch Switching
Switching between git branches with fzf is one of those workflows that sounds marginal until you try it:
# Fuzzy git branch switch
fbr() {
git branch --all | grep -v HEAD | sed 's/remotes\/origin\///' | sort -u |
fzf --preview 'git log --oneline --graph --color=always {}' |
xargs git checkout
}
Add that function to your shell config and you can switch branches by typing a few characters of the name rather than typing it in full. The preview pane shows the recent commit history of each branch as you select it.
Similarly useful for interactively selecting commits, tags, or stashes.
Content Search: Combining fzf with ripgrep
The combination of rg (ripgrep) for content search and fzf for interactive selection is powerful for codebases. The standard pattern:
# Interactive content search with file preview
rg --color=always --line-number --no-heading '' |
fzf --ansi --delimiter : \
--preview 'bat --color=always {1} --highlight-line {2}' \
--preview-window 'right:60%:+{2}-/2'
Or as a tighter function that opens the selected file at the matching line in your editor:
rgv() {
local result
result=$(rg --color=always --line-number --no-heading "$1" |
fzf --ansi --delimiter : \
--preview 'bat --color=always {1} --highlight-line {2}' \
--preview-window 'right:60%:+{2}-/2')
[ -n "$result" ] && vim "$(echo "$result" | cut -d: -f1)" "+$(echo "$result" | cut -d: -f2)"
}
Call rgv "search term" and you get an interactive list of matching lines across all files, with a preview of each file at the matching line, and pressing Enter opens the file in vim at that line.
Kill Processes Interactively
Killing processes by typing kill -9 <pid> after a ps aux | grep something is tedious. With fzf:
fkill() {
ps aux | tail -n +2 | fzf -m | awk '{print $2}' | xargs kill -${1:-9}
}
fkill opens a searchable list of all running processes. You can multi-select with Tab, then kill them all at once. Way faster than the manual workflow.
Useful Configuration Options
A few fzf options worth knowing:
--multi (-m): allows selecting multiple items with Tab.
--height: sets the height of the fzf window as a percentage of the terminal, which is less disorienting than full-screen mode.
--reverse: shows the input list from top to bottom instead of bottom to top (matter of preference).
--border: adds a rounded border around the fzf window.
--preview-window hidden: hides the preview pane by default; toggle it with Ctrl+/.
A comfortable set of defaults for your shell config:
export FZF_DEFAULT_OPTS='
--height=50%
--border=rounded
--reverse
--bind "ctrl-/:toggle-preview"
--color=16
'
Worth It?
fzf is the kind of tool that slots into existing workflows rather than replacing them. Ctrl+R alone is worth the five minutes of setup, and each additional workflow (file search, branch switching, process killing, interactive log browsing) adds incrementally. It works on Linux, macOS, and WSL without friction, and it’s been stable and maintained for over a decade.
Install it, run the install script, and see how often you reach for Ctrl+R instead of pressing it repeatedly. That answer will tell you whether it’s worth investing in the other integrations.