fzf is a general-purpose command-line fuzzy finder. It’s incredibly fast and can be integrated with your shell to enhance common workflows like searching through command history, files, and directories.

Let’s see fzf in action. Imagine you want to find a specific command you ran a while ago, but you only remember a few keywords. Instead of history | grep "keyword", you can hit Ctrl+R (or whatever keybinding you set up).

$ # Hit Ctrl+R
$ # Type a few characters, e.g., "git comm"
$ git commit -m "Refactor user authentication"

fzf instantly filters your entire command history. You can navigate with arrow keys or Ctrl+J/Ctrl+K and press Enter to execute the selected command. It’s not just history; you can use it for files too.

$ # Type 'vim ' then hit Ctrl+T
$ vim src/components/AuthForm.js

Ctrl+T opens fzf to fuzzy-find files and directories in your current directory and its subdirectories. Again, type a few characters, and fzf narrows down the list. Select the file with arrow keys and press Enter to open it in vim.

The real power comes from how it’s integrated. When you install fzf, it typically provides shell scripts that hook into your shell’s functions. For Zsh, this usually involves sourcing a script that defines functions like __fzf_history__ and __fzf_file__ and then binds them to key shortcuts.

Here’s a simplified look at what might be in your .zshrc after installing fzf:

# ~/.zshrc

# Source fzf keybindings and fuzzy completion
[ -f ~/.fzf.bash ] && source ~/.fzf.bash
[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh

# Example custom binding for finding directories
bindkey '^X^D' fzf-cd

The source ~/.fzf.zsh line is where the magic happens. It loads Zsh functions and key bindings provided by the fzf installation. bindkey '^X^D' fzf-cd is a custom binding I added to use fzf to change directories. Typing Ctrl+X Ctrl+D will now launch fzf, allowing you to fuzzy-find a directory and cd into it.

The core of fzf’s integration lies in its use of shell functions and command substitution. For history search (Ctrl+R), fzf typically works by:

  1. Getting your entire command history (e.g., from $HISTFILE or Zsh’s internal history).
  2. Piping this history to fzf.
  3. When you select a command and press Enter, fzf prints that selected command to standard output.
  4. Your shell then takes that output and, depending on the binding, either executes it directly, inserts it into the current command line, or uses it as an argument for another command.

For file finding (Ctrl+T), it’s similar but uses find (or similar tools) to generate a list of files and directories, which is then piped to fzf.

The mental model to build here is that fzf isn’t just a standalone tool; it’s a highly customizable filter and selector that sits between your shell’s input/output and the commands you execute. You configure your shell to call fzf with specific data, and then your shell reacts to what fzf outputs.

The "fuzzy" part means it uses an algorithm that matches characters in the order they appear, but allows for arbitrary characters in between. So, term file will match terminal_file.txt and my_term_file.sh. It’s not a regular expression search, which is why it’s so fast and intuitive for quick lookups.

Here’s a detail many users overlook: fzf’s input can be structured. When you use Ctrl+T to find files, the output is just the file path. But you can pipe any list of strings to fzf. This allows for incredibly powerful custom scripts. For instance, you could create a script that lists all your Git branches, pipes them to fzf, and then uses the selected branch to run git checkout <selected_branch>.

# Example: Custom script to checkout a git branch using fzf
function fzf_git_checkout() {
  local branches
  branches=$(git branch --format='%(refname:short)')
  local selected_branch
  selected_branch=$(echo "$branches" | fzf --prompt="Checkout branch: ")
  if [[ -n "$selected_branch" ]]; then
    git checkout "$selected_branch"
  fi
}
bindkey '^G^B' fzf_git_checkout # Bind to Ctrl+G Ctrl+B

This script demonstrates piping git branch output to fzf and then using the selection. The --prompt option customizes the prompt fzf displays.

The next step is to explore fzf’s extensive options for customizing the look and behavior, such as changing the layout, colors, key bindings, and the preview window.

Want structured learning?

Take the full Zsh course →