Mastering fzf's search pattern language: fuzzy default, exact, prefix, suffix, invert, and OR, plus case control and how to understand scores and result ordering with the v1 and v2 algorithms.

After episode 2 dissected fzf's architecture — the stdin filter stdout model, subsequence matching, and exit codes — now it is time to master the tool you will use most every day: the search pattern language. This episode is the heart of "feeling fast" with fzf: once these patterns stick, you will no longer retype full paths or stare at long lists.
There is one key concept: modern fzf has extended search enabled by default. That means certain symbols at the start of a word you type change the meaning of the pattern. You don't need to memorize a menu — just type the pattern, and fzf understands what you mean.
Each query you type into fzf can contain several "words", and each word can be given a special meaning through symbols. These five patterns are the foundation:
| Pattern | Example | Meaning |
|---|---|---|
| Fuzzy (default) | fzf | Characters in order, gaps allowed |
| Exact | 'fzf | Characters exactly in order, no gaps |
| Prefix | ^learn | Item must start with learn |
| Suffix | .md$ | Item must end with .md |
| Invert | !test | Item must not contain test |
Compare the first two patterns: with fzf (fuzzy), the item learn-fzf matches — and so does fzf.md. But with 'fzf (exact), the item must contain the letters f, z, f consecutively without gaps — fzf.md still matches, while lxfzf does not. This is the fundamental difference between "gaps allowed" and "must be consecutive".
Prefix and suffix patterns are very useful for narrowing a list drastically. Type ^docker if you only want items that start with docker, or config$ if you only want those that end with config. Invert, meanwhile, is a "rejection filter": !test removes every item containing test from the list — very handy for hiding irrelevant files.
printf "server-prod.conf\nserver-staging.conf\ndb-prod.yaml\ndb-dev.yaml\nnotes.md\nREADME.md\n" | fzfTry the combinations: type prod (plain fuzzy), then ^db (only items starting with db), then !yaml (exclude all yaml files). Notice how the list shrinks gradually — that is how you talk to fzf every day.
Beyond the five basic patterns, there is one more you must know: OR. The | symbol inside a query means "match either one".
| Pattern | Example | Meaning |
|---|---|---|
| OR | prod | dev | Item matches prod or dev |
On the dataset above, the query prod | dev shows all five files (every one contains either word). One thing to remember: the OR pattern only works if you are using extended search. If it is disabled with --no-extended, the | symbol is treated as a regular character.
Note
Note that the ^, $, and ! symbols are only treated as pattern markers when extended search is active (the default) and the symbol sits at the start of a word in the query. In the middle of a word, these symbols are treated as ordinary characters — so file! will fuzzy-search the string file!, not exclude something.
fzf's case behavior follows the smart-case principle: by default, fzf ignores case differences as long as your query is all lowercase. As soon as your query contains an uppercase letter, matching becomes case-sensitive. This makes sense: when you type server you want everything, but when you type Server you usually really mean exactly Server.
Two options control this behavior explicitly:
| Option | Meaning |
|---|---|
-i / --ignore-case | Always ignore case differences |
-I / --no-ignore-case | Always respect case differences |
printf "Server\nserver\nSERVER\n" | fzf -i
printf "Server\nserver\nSERVER\n" | fzf -IWith -i, the query server will match all three. With -I, only server matches. The most common real-world choice: keep the default smart-case, and use -i only if your list is full of uppercase abbreviations.
Beyond the per-word 'term pattern, fzf provides --exact to change the behavior of the entire query. With --exact, fuzzy matching is turned off and every word is treated as an exact search (characters consecutive, no gaps).
printf "learn-fzf\nlxfzf\nfzf\n" | fzf --exactIn the example above, the query fzf in exact mode only matches items that contain f, z, f consecutively without gaps — learn-fzf and fzf match, lxfzf does not. This mode is useful for short lists, such as branch or tag lists, where fuzzy matching is too loose and often surfaces unwanted results.
Every matching item gets a score, and fzf sorts results from highest score down. Several factors raise the score:
fzf inside fzf scores far higher than a scattered fzf in lxfzf or lear-f-f-z.As a result, fzf's result order is almost always "the most sensible at the top" — not the original list order. This is good behavior, but important to be aware of, because beginners are often confused when the list changes order as they type.
This ordering is also determined by the chosen scoring algorithm. fzf provides two generations via --algo:
| Option | Characteristics |
|---|---|
--algo=v2 | Modern algorithm (default); more intuitive and consistent result ordering |
--algo=v1 | Old algorithm from early versions; for compatibility and classic behavior |
printf "fzf.md\nfz.md\nfzf\n" | fzf --algo=v2
printf "fzf.md\nfz.md\nfzf\n" | fzf --algo=v1With the query fzf, notice how the relative positions of fzf.md and fz.md can differ between v1 and v2. The rule of thumb: keep --algo=v2 as the default, and only drop to v1 if you have a strong reason — for example, results you have memorized from an older version.
In this episode 3, you mastered fzf's search pattern language: fuzzy (default), exact with ', prefix with ^, suffix with $, invert with !, and OR with |. You also understood case control (-i/-I and smart-case), the global exact mode --exact, and how scores and --algo determine result ordering.
The key takeaways:
', ^, $, !, | work immediately.'term = exact, ^term = prefix, term$ = suffix, !term = exclude, a \| b = either.-i/-I for explicit control.--exact disables fuzzy matching for the whole query.--algo=v1/v2 changes scoring behavior.In the next episode, episode 4, we will make fzf's appearance your own: interactive UI & layout — height, layout, border, margin, padding, the info line, and customizing the prompt, pointer, marker, header, and colors. See you in episode 4!