32blogby StudioMitsu

fzf Complete Guide: Fuzzy Finding That Changes Everything

Install fzf, integrate with your shell, supercharge Ctrl+R and Ctrl+T, connect with Git, and customize it for your workflow.

9 min read
On this page

"Where was that file again?" "What was that command I ran three days ago?" "I have too many Git branches to keep track of."

Searching is one of the biggest time sinks in terminal work. history | grep and find . -name only get you so far.

Enter fzf — a fuzzy finder that lets you interactively search files, command history, Git branches, processes, and virtually anything else. Once you start using it, there's no going back to plain Ctrl+R.

What is fzf?

fzf is an interactive fuzzy finder written in Go by junegunn (also known for vim-plug and fzf.vim).

It follows the UNIX philosophy: read lines from stdin, let the user pick one, and write it to stdout. This "take anything, return anything" design makes fzf a universal tool that plugs into any workflow.

Key features:

  • Fuzzy matching: you don't need exact strings — partial keywords narrow down results instantly
  • Blazing fast: v0.70.0 improved filtering performance by 1.3–1.9x. Tens of thousands of files are no problem
  • Shell integration: supercharges Ctrl+R (history search), Ctrl+T (file path insertion), and Alt+C (directory jump)
  • Preview: see file contents or Git diffs in real time before selecting
  • Pipes into anything: filter output from find, git, ps, docker — any command that produces lines

Installation and setup

If you're using WSL, follow the Linux instructions above.

For PowerShell:

powershell
winget install junegunn.fzf

Shell integration

fzf 0.48+ greatly simplified shell integration. Add the following to your shell config:

For bash (~/.bashrc):

bash
eval "$(fzf --bash)"

For zsh (~/.zshrc):

bash
source <(fzf --zsh)

Apply the changes:

bash
source ~/.bashrc  # for bash
source ~/.zshrc   # for zsh

Basic usage

Fuzzy search files

Run fzf with no arguments to list all files under the current directory and interactively narrow them down.

bash
fzf

Any file whose path contains the characters you type will remain as a candidate. You don't need an exact match — typing cnf matches config, conf.yaml, nginx.conf, and more.

Pipe input into fzf

This is where fzf really shines.

bash
# Search only JavaScript files
find . -name "*.js" | fzf

# Search environment variables
env | fzf

# Search recent commands
history | fzf

Select multiple items

The -m (--multi) flag enables multi-select with Tab.

bash
# Select multiple files and delete them
rm $(fzf -m)

Preview files while selecting

The --preview option displays file contents alongside the candidate list. If you have bat installed, you get syntax highlighting for free.

bash
# Preview with cat
fzf --preview 'cat {}'

# Preview with bat (syntax-highlighted)
fzf --preview 'bat --color=always {}'

Start with an initial query

Use -q to pre-fill the search field.

bash
fzf -q "test"

Pass the result to another command

Use $(fzf) to feed the selected file into any command.

bash
# Open the selected file in vim
vim $(fzf)

# Open the selected file in VS Code
code $(fzf)

Shell integration

Shell integration is fzf's killer feature. Learn three key bindings and your terminal experience will transform.

Ctrl+R — fuzzy search command history

fzf replaces the shell's built-in Ctrl+R (reverse-i-search):

  • Standard Ctrl+R: steps through history one entry at a time
  • fzf's Ctrl+R: fuzzy-searches the entire history and finds what you need instantly
bash
# How to use: press Ctrl+R at the prompt
# → fzf opens with your full command history
# → type keywords to narrow down
# → press Enter to insert the selected command

That docker-compose command from three days ago? Just type dock and it's right there.

Ctrl+T — insert a file path

Press Ctrl+T while typing a command to search for a file and insert its path.

bash
# How to use:
# type "vim " then press Ctrl+T
# → fzf opens, you search and select a file
# → "vim path/to/selected/file" appears on your command line

Far faster than Tab-completing through deep directory trees.

Alt+C — jump to a directory

Press Alt+C to fuzzy-search directories and cd into the selected one.

bash
# How to use: press Alt+C
# → fzf displays a directory listing
# → select one and cd runs automatically

No more cd + Tab + Tab + Tab to drill down into nested folders.

Customize the default commands

You can control what fzf lists by setting environment variables. fd (a fast, Rust-based find alternative) automatically respects .gitignore and runs much faster.

bash
# If fd is installed (add to .bashrc / .zshrc)
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
export FZF_ALT_C_COMMAND='fd --type d --hidden --follow --exclude .git'

See Modern Rust CLI Tools for more on fd.

Real-world use cases

fzf's real power comes from combining it with other commands. Here are patterns you can use right away.

Supercharge Git operations

Git gets harder to navigate as branches and commits pile up. fzf makes it effortless.

bash
# Fuzzy-search and switch branches
git checkout $(git branch --all | fzf)

# Fuzzy-search commits (with diff preview)
git log --oneline | fzf --preview 'git show {+1}'

# Fuzzy-search changed files (with diff preview)
git diff --name-only | fzf --preview 'git diff {}'

Find and kill processes

Hunting down a runaway process is a one-liner with fzf.

bash
# Search for a process and kill it
kill $(ps aux | fzf | awk '{print $2}')

# Force kill
kill -9 $(ps aux | fzf | awk '{print $2}')

Combine ripgrep results with fzf to search your codebase and preview matches in context. Perfect for finding TODOs or error patterns.

bash
# Search for TODO comments with preview
rg --line-number "TODO" | fzf --delimiter ':' --preview 'bat --color=always --highlight-line {2} {1}'

Docker container operations

Select a running container and drop into its shell.

bash
# Pick a container and start bash
docker exec -it $(docker ps --format '{{.Names}}' | fzf) bash

# View container logs
docker logs --tail 100 $(docker ps --format '{{.Names}}' | fzf)

SSH host selection

Pick a host from your ~/.ssh/config and connect.

bash
# Fuzzy-search SSH hosts
ssh $(grep "^Host " ~/.ssh/config | awk '{print $2}' | fzf)

Customization

Default options

The FZF_DEFAULT_OPTS environment variable controls fzf's appearance and behavior.

bash
# Add to .bashrc / .zshrc
export FZF_DEFAULT_OPTS='
  --height 40%
  --layout=reverse
  --border
  --info=inline
  --margin=1
  --padding=1
'
  • --height 40%: use only 40% of the screen (no fullscreen takeover)
  • --layout=reverse: show candidates top-to-bottom (default is bottom-up)
  • --border: draw a border around the finder
  • --info=inline: show match count on the prompt line

Color scheme

Customize colors with the --color option.

bash
export FZF_DEFAULT_OPTS='
  --height 40%
  --layout=reverse
  --border
  --color=fg:#c0caf5,bg:#1a1b26,hl:#bb9af7
  --color=fg+:#c0caf5,bg+:#292e42,hl+:#7dcfff
  --color=info:#7aa2f7,prompt:#7dcfff,pointer:#ff007c
  --color=marker:#9ece6a,spinner:#9ece6a,header:#9ece6a
'

Key binding customization

The --bind option lets you add custom key bindings inside fzf.

bash
export FZF_DEFAULT_OPTS='
  --height 40%
  --layout=reverse
  --border
  --bind "ctrl-y:execute-silent(echo {} | xclip -selection clipboard)"
  --bind "ctrl-e:execute(vim {})"
'
  • ctrl-y: copy the current item to the clipboard
  • ctrl-e: open the current file in vim

Shell functions for common patterns

Wrap frequently used patterns in shell functions. Add these to ~/.bashrc or ~/.zshrc.

bash
# Pick a file with preview and open in vim
fv() {
  local file
  file=$(fzf --preview 'bat --color=always {}' --height 80%)
  [ -n "$file" ] && vim "$file"
}

# Switch Git branches with fzf
fb() {
  local branch
  branch=$(git branch --all | fzf --height 40% | sed 's/^[* ]*//' | sed 's|remotes/origin/||')
  [ -n "$branch" ] && git checkout "$branch"
}

# cd into a directory with preview
fd_cd() {
  local dir
  dir=$(find . -type d 2>/dev/null | fzf --preview 'ls -la {}' --height 60%)
  [ -n "$dir" ] && cd "$dir"
}

Wrapping Up

fzf takes the simple concept of fuzzy matching and, through the UNIX pipe philosophy, turns it into a universal tool.

Here's all you need to get started:

  1. Install fzf and enable shell integration (add eval "$(fzf --bash)" to .bashrc)
  2. Start using Ctrl+R / Ctrl+T / Alt+C (immediate productivity boost)
  3. Install fd and bat, then set them as defaults (faster search, better previews)

These three steps give you the bulk of fzf's benefits. As you get comfortable, add Git integrations and shell functions to build a workflow that's uniquely yours.

Related articles: