The most surprising thing about fzf is that it’s not just a fuzzy finder; it’s a general-purpose command-line multiplexer that happens to be incredibly good at fuzzy finding.

Let’s see it in action. Imagine you’re deep in a project, and you need to jump to a specific file. Instead of find or :ls and then :b, you hit Ctrl+P (or whatever your fzf keybinding is). A list of files and buffers appears, and as you type, it instantly filters them.

# Example of what you might type in fzf after hitting Ctrl+P
> src/compone<TAB>

fzf doesn’t just do exact matches. It uses a sophisticated fuzzy matching algorithm. When you type compone, it looks for files that have c, then later o, then later m, then later p, then later o, then later n, then later e in that order, anywhere in the filename. The gaps between characters are what make it "fuzzy." It’s like a highly forgiving grep for filenames.

Here’s the core mental model: fzf takes a stream of input lines, displays them in an interactive, filterable list, and then outputs the selected line(s) to standard output. Your Vim configuration then consumes that output.

The typical Vim setup for fzf involves a few key components:

  1. The fzf executable: You need to install it separately. On macOS, brew install fzf. On Linux, download it from the GitHub releases page or use your package manager (apt install fzf, dnf install fzf).
  2. Vim plugin (optional but recommended): Plugins like fzf.vim or fzf-lua provide convenient Vim commands and keybindings that integrate fzf seamlessly.
  3. Vim configuration: You’ll map keys to specific fzf commands.

Let’s look at the fzf.vim plugin’s common commands:

  • :Files: Searches for files in the current directory and its subdirectories.
  • :Buffers: Searches through currently open buffers.
  • :Ag or :Rg: Uses ag (the Silver Searcher) or rg (ripgrep) to search for content within files, with fzf providing the interactive selection.

Here’s a snippet from a typical vimrc using fzf.vim:

" --- fzf ---
" Use Ctrl+P for file searching
nnoremap <silent> <C-P> :Files<CR>
" Use Ctrl+B for buffer searching
nnoremap <silent> <C-B> :Buffers<CR>
" Use Ctrl+S for content searching with ripgrep
nnoremap <silent> <C-S> :Rg<CR>

" Configure fzf.vim to use fzf
let g:fzf_command_prefix = 'Fzf' " Default is 'FZF'

" Optional: Customize fzf options
" let g:fzf_opts = ['--reverse', '--preview', 'head -n 50 {}']

When you press <C-P>, Vim executes :Files<CR>. The fzf.vim plugin constructs a command like find . -type f | fzf, pipes the output of find into fzf, and displays the interactive list. When you select a file and press Enter, fzf outputs the chosen filename, which fzf.vim then uses to open that file in Vim (e.g., :e /path/to/selected/file).

The real magic is how fzf handles the selection and piping. It’s not just a simple grep. It uses a scoring algorithm based on character matches, contiguous matches, and positional information to rank results. This is why typing src/compone will likely show src/components/MyComponent.js higher than src/utils/compose.js, even though both contain the necessary characters.

When you use :Rg (or :Ag), fzf.vim constructs a command like rg --line-number --no-heading --smart-case '' . | fzf --delimiter : --nth 3.. --preview '...'. The output of rg is piped into fzf. fzf then parses this output, typically filename:line_number:matched_text, and allows you to select a specific line. The --delimiter : --nth 3.. tells fzf to use the colon as a separator and consider the third field onwards for searching, effectively letting you search by the matched text itself. The --preview option shows you the context of the selected line, often using bat or cat to display the file content.

The --preview option in fzf is incredibly powerful. When fzf.vim uses it with :Rg, it might look something like: --preview 'bat --color=always --highlight-line {2} {1}' This tells fzf to run bat (a cat clone with syntax highlighting) on the file specified by {1} (the filename) and highlight the line number specified by {2}. This provides immediate context for your search results without leaving the fzf interface.

The next step in mastering fzf in Vim is understanding how to customize its behavior beyond the defaults, especially for more complex workflows like Git history searching or command history searching.

Want structured learning?

Take the full Vim course →