fzf is a command-line fuzzy finder: it reads a list on standard input, shows an interactive picker, and prints whatever you select. The Windows binary is a single 6235136-byte executable with no installer and no runtime.

The problem it solves is "I know part of the name." Typing a full path into a shell means remembering where things live; fzf lets you type three characters of the middle and narrows 5228 candidates down to the ones that match.

I measured two things on this machine: the non-interactive filter path, which is what scripts use, and the interactive picker. Both ran against a 5228-line file listing produced from a 5000-file directory tree.

A single 6235136-byte executable

The release zip is 2544236 bytes and contains exactly one file. There is no lib directory, no config template, and no registry write on first run.

ItemValueNote
Release zip2544236 bytesfzf-0.74.5-windows_amd64.zip
fzf.exe6235136 bytesThe only file in the archive
Files after unpack1No assets, no themes
Version command158 msThen 134 and 175 ms

Version and build hash

# Three runs: 158 / 134 / 175 ms
fzf --version
0.74.5 (c0a193e0)

The second half of that line is the commit hash. It is the only reliable way to tell whether a downloaded binary matches a tag, since the file name does not carry the commit.

It is not a shell integration by itself

fzf only does the picking. The familiar Ctrl-R history search and Ctrl-T file insertion come from shell scripts that ship with the Unix packages, and this Windows zip has none of them. On Windows you either pipe a list into fzf yourself or use it with a wrapper. That part was not tested here.

Filtering 5228 paths

The test corpus was built with dir /s /b over a tree of 5000 files in 100 directories, giving 5228 lines. Feeding it through --filter runs fzf in batch mode: no interaction, just matching.

QueryHitsWall time
mod_3 (fuzzy)1300136 / 139 / 137 ms
README with -e (exact)800144 / 135 / 135 ms
Input lines5228One line per path
Process start158 msSame order as the filter itself

Most of the 136 ms is process start

A 158 ms cold start and a 136 ms filter run are the same magnitude, which means matching 5228 lines costs almost nothing and the executable launch dominates. On lists of this size the algorithm is not the bottleneck.

Fuzzy and exact are the same speed here

Fuzzy matching returned 1300 hits in 136 ms; exact matching returned 800 in 135 ms. With 5228 lines there is no measurable difference, so pick the mode by what you want to match, not by performance.

# Batch mode: filter a piped list, print matches, exit
dir /s /b tree | fzf --filter mod_3
# Exact substring instead of fuzzy
dir /s /b tree | fzf --filter README -e

What the picker actually shows

Run without --filter, fzf takes over the console: a prompt line at the bottom, a match counter, and the candidate list above it. The screenshot was taken with --query mod_3 so the state is reproducible without typing.

ElementObservedMeaning
Prompt line> mod_3Characters you have typed
Counter1300/5228Matches over total candidates
ListHighlighted substringsWhich characters matched
SelectionRight-hand markerCurrent row, moved with arrows

The counter is the useful part

1300/5228 tells you how much the query narrowed things. If the first character drops the count from 5228 to 2600 and the third barely moves it, the query is not doing the work you think it is.

Highlighting shows why a row matched

fzf highlights each matched character, not the whole line. That is how you spot a bad match: three scattered characters across a path with nothing in common is a false positive even though the algorithm scored it.

fzf picker with --query mod_3 over 5228 paths: prompt line at the bottom shows 1300/5228, matched characters highlighted in each row

Before you install it

There is nothing to configure and nothing to uninstall. What matters is the terminal, because the picker needs cursor control and a console without it will show garbage instead of a list.

ItemObserved hereNote
SystemWindows 10 22H2 (19045.6466)Official windows_amd64 build
Consolecmd.exe with VT enabledPicker renders correctly
Config filesNone writtenFlags only
LicenseMITCommercial use allowed

Legacy consoles show escape codes

A console without virtual terminal processing prints the cursor-control sequences as literal text. Nothing is broken in fzf; the host cannot interpret the output. Enabling VT for the console fixed it in this test.

Pass the list in, do not expect it to find files

fzf never touches the filesystem. If the list is empty the picker shows nothing, which looks like a failure but is usually a broken pipe upstream. Verify with dir | find /c /v "" that the producer emits lines before blaming fzf.

Three things that cost time

Empty input looks like a hang

A producer that writes to standard error instead of standard output leaves fzf with 0 lines, and the window sits there with an empty list. Check the line count first.

Default mode is not exact matching

Typing mod_1 also matches mod_13 and any path where those characters appear in order. Add -e when a substring has to appear intact, or anchor with ^ and $.

Batch mode ignores the display

--filter returns all matches, not the one you would have picked. Used in a script it prints 1300 lines for the query above; add --select-1 or take the first line yourself if a script needs exactly one.

When it earns a place

Any workflow where a command needs a path argument is a candidate. Git checkout of a branch you half-remember, opening one log file out of thousands, picking a process to kill: the picker costs 136 ms and removes the guesswork.

If you already type full paths confidently, or your lists are under a hundred lines, this adds a step without removing one. The value shows up on 5000-line lists, which is exactly where a shell's tab completion gives up.

ItemValue
fzf.exe6235136 bytes
Release zip2544236 bytes
Filter 5228 lines136 ms, 1300 hits
Exact filter135 ms, 800 hits
Cold start158 ms