Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

fzf Administrator & Developer Guide

Generated April 2026 from junegunn/fzf at 06e7057

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is the operational and architectural reference for fzf. It covers the build/release process, the full configuration surface (every CLI flag, every environment variable, every action), the internal architecture (reader → matcher → terminal pipeline), security posture, performance tuning, and the integration points with shells, tmux, Zellij, and editors.

The companion User Guide covers everyday usage; this guide assumes familiarity with that material.

1. Architecture Overview

fzf is a single-binary Go program that runs as an interactive TTY filter. Source input enters a non-blocking reader, passes through a parallel matcher that scores items with a fuzzy or exact algorithm, and the result is displayed by a terminal renderer that handles user input events, the preview window, and any command bindings the user has set.

                +-----------------+
                | stdin / command |
                +--------+--------+
                         |
                         v
                +--------+--------+      +----------------+
                |     Reader      |----->|   ChunkList    |
                |  (src/reader.go)|      | (src/chunklist)|
                +--------+--------+      +-------+--------+
                         | EvtReadNew           |
                         | EvtReadFin           |
                         v                       v
                +--------+--------+      +-------+--------+
                |     Core        |<---->|     Matcher    |
                | (src/core.go)   |      | (src/matcher.go)
                +--------+--------+      +-------+--------+
                         |                       |
                         | EvtSearchNew/Progress/Fin
                         v                       |
                +--------+--------+              |
                |    Terminal     |<-------------+
                | (src/terminal.go)|
                +--------+--------+
                         |
                         | renders to TUI:
                         |   - LightRenderer (xterm escape codes)
                         |   - tcell Renderer (Windows/legacy)
                         |
                         v
                +--------+--------+
                |  src/tui (TUI)  |
                +-----------------+

Note

The Reader, Matcher, and Terminal each run in their own goroutine and communicate via an EventBox (see src/util/eventbox.go). The coordinator delays UI updates by up to 100ms to coalesce rapid input changes — a fundamental design decision that keeps fzf responsive even on inputs of millions of lines.

1.1 Component inventory

Component Path Role
Entry point main.go Parses options, prints embedded shell scripts on --bash/--zsh/--fish, prints embedded man page on --man, otherwise calls fzf.Run(options).
Core orchestrator src/core.go Wires Reader → Matcher → Terminal goroutines and dispatches events.
Option parser src/options.go The big one (~3900 lines): parses every CLI flag, --bind actions, --color specs, --preview-window specs, and validates them.
Reader src/reader.go Reads input from stdin or FZF_DEFAULT_COMMAND non-blockingly, chunks lines, signals via EventBox.
Chunk list src/chunklist.go Lock-free append-only list of 1024-line chunks. Lets the Matcher and Terminal observe the input without blocking the Reader.
Matcher src/matcher.go Spawns N partitions (default = runtime.NumCPU()), each running the configured algorithm. Caches Pattern-keyed results (ChunkCache).
Pattern parser src/pattern.go Tokenises queries into termSets (AND-of-OR semantics) — implements the search-syntax grammar (', ^, $, !, |).
Algorithms src/algo/algo.go + SIMD asm FuzzyMatchV1, FuzzyMatchV2, ExactMatchNaive, ExactMatchBoundary, PrefixMatch, SuffixMatch, EqualMatch. AMD64/ARM64 SIMD indexbyte2 accelerator.
Terminal src/terminal.go The other big one (~17 000 lines): event loop, layout, list/preview/header/footer/prompt rendering, mouse, jump mode, history widget, popup.
TUI back-ends src/tui/light.go, src/tui/tcell.go LightRenderer issues raw xterm escape codes (Unix); the tcell renderer is used on Windows and legacy terminals.
Server src/server.go Hand-rolled HTTP/1.1 server (no net/http) for --listen — receives action sequences, validates X-API-Key, dispatches via channel.
Tmux launcher src/tmux.go Implements --tmux / --popup by exec'ing tmux display-popup.
Zellij launcher src/zellij.go Same idea for Zellij ≥ 0.44.
Process protector src/protector/ OpenBSD-only pledge/unveil hardening. No-op on other OSes.
Proxy src/proxy.go, src/proxy_unix.go, src/proxy_windows.go Plumbing for become(...) — exec-replacement of fzf.
WinPTY src/winpty.go, src/winpty_windows.go Windows-specific terminal lifecycle workaround for ConEmu / mintty.
Shell scripts shell/key-bindings.{bash,zsh,fish}, shell/completion.{bash,zsh,fish}, shell/common.sh Embedded into the binary at build time and emitted via --bash/--zsh/--fish.
Vim plugin plugin/fzf.vim Provides :FZF and helpers; the rich plugin is a separate repo.

1.2 Technology stack

Layer Tech
Language Go 1.23
TUI library github.com/gdamore/tcell/v2 v2.9.0 (Windows / legacy fallback)
Direct TUI hand-rolled escape-code renderer (src/tui/light.go) for performance on Unix
File walker github.com/charlievieth/fastwalk v1.0.14 (used by --walker)
Word splitting github.com/junegunn/go-shellwords (POSIX shell tokenisation for --bind action arguments)
TTY detection github.com/mattn/go-isatty v0.0.20
Unicode segmentation github.com/rivo/uniseg v0.4.7 (grapheme-aware width computation)
Low-level golang.org/x/sys v0.35.0, golang.org/x/term v0.34.0
Test framework minitest 5.25.4 (Ruby) for end-to-end shell-integration tests; Go testing for unit tests
Lint rubocop for the Ruby tests; gofmt -s and go vet for Go
Build Makefile + GoReleaser (.goreleaser.yml)

1.3 Data flow for a typical run

  1. main.go calls fzf.ParseOptions (src/options.go).
  2. The parser validates every flag; on error it returns immediately (exit(ExitError, err)).
  3. fzf.Run(options) builds a Reader, Matcher, and Terminal, all communicating through a shared EventBox.
  4. Reader.ReadSource() runs in its own goroutine. If stdin is a TTY and FZF_DEFAULT_COMMAND is set, it execs that command. Otherwise it reads stdin. Items are appended to a ChunkList.
  5. Whenever a new chunk appears, Reader posts EvtReadNew to EventBox. When stdin closes, it posts EvtReadFin.
  6. Matcher.Loop listens for EvtReadNew, takes the latest Pattern, and runs N parallel scoring passes (one per CPU). Results are merged and cached.
  7. Terminal.Loop listens for EvtSearchNew, EvtSearchProgress, and EvtSearchFin, updating the screen accordingly. It also reads keyboard / mouse events and dispatches the bound actions.
  8. On accept, the selected item(s) and the optional --print-query are written to stdout and fzf exits with ExitOk (0).
  9. On become(...), the selected item is templated into the command and syscall.Exec replaces the fzf process.

1.4 Concurrency model

Three goroutines (Reader, Matcher, Terminal) plus a coordinator. The coordinator schedules screen updates with adaptive delay (coordinatorDelayMax = 100ms, step 10ms) so that bursts of input or keystrokes coalesce into a single render pass.

The Matcher partitions the chunk list across runtime.NumCPU() goroutines (override with --threads N). Each partition uses its own slab allocator (util.Slab) to minimise GC pressure during high-rate matching.

2. System Requirements

2.1 Runtime requirements

Layer Requirement
Operating system Linux (any distro, glibc or musl), macOS 10.15+, Windows 10/11 (Terminal, ConEmu, mintty), FreeBSD, OpenBSD, Android (via Termux).
Architecture amd64, arm64, arm v5/v6/v7, ppc64le, s390x, riscv64, loong64.
Terminal Any terminal that handles xterm-style escape codes. Modern Windows Terminal, iTerm2, Alacritty, kitty, gnome-terminal, Konsole, mintty, ConEmu — all known-good.
Shell Optional integration scripts target Bash 3.2+, Zsh 5.0+, Fish 3.0+. fzf itself is shell-agnostic.
Disk <8 MB binary; no persistent state.
Memory A few MB at startup; scales with input. ~30 bytes per item plus pattern cache. 10 million items ≈ ~300 MB resident.
Network None. fzf is fully offline by default. The --listen server only opens when explicitly requested.

2.2 Build requirements

Layer Requirement
Go 1.23 or newer (matches go.mod).
Make Optional — the Makefile orchestrates build, embed, and release.
GoReleaser Required for cross-arch release artifacts (matches .goreleaser.yml). Set GORELEASER_VERSION in .tool-versions.
Ruby 3.x with bundler — for the integration test suite (tests/test_*.rb).
Tools shfmt for shell-script formatting, rubocop for Ruby lint.

2.3 Platform-specific notes

Platform Note
OpenBSD The binary calls pledge/unveil (src/protector/protector_openbsd.go) at startup to drop dangerous privileges.
Windows Uses the tcell renderer instead of the raw light renderer; supports ConEmu via ConEmuPID. WinPTY (src/winpty_windows.go) handles legacy mintty/Cygwin terminals.
macOS The shell-integration scripts detect that macOS's stock awk chokes on non-UTF-8 and prefer mawk or GNU awk if installed.
Solaris The integration scripts use /usr/xpg4/bin/awk (POSIX-conformant) instead of the legacy /usr/bin/awk.
Android goreleaser builds a linux_arm64 artifact suitable for Termux.

3. Configuration Reference

fzf is configured exclusively through CLI flags and environment variables. Settings precedence (lower wins, higher overrides):

  1. Flags from FZF_DEFAULT_OPTS_FILE
  2. Flags from FZF_DEFAULT_OPTS
  3. Flags on the command line

3.1 Environment variables

Variable Type Default Description Required?
FZF_DEFAULT_COMMAND shell command find . -type f (when no --walker) Command to run when stdin is a TTY. Output is treated as the candidate list. No
FZF_DEFAULT_OPTS string empty Extra CLI options applied to every fzf invocation. Whitespace-separated; supports newlines. No
FZF_DEFAULT_OPTS_FILE path empty Path to a file of default options. Read before FZF_DEFAULT_OPTS. No
FZF_API_KEY string empty API key for the HTTP server (--listen). Required when binding non-locally. When non-local --listen
FZF_CTRL_T_COMMAND shell command platform default Used by the CTRL-T file widget. Set to empty string to disable. No
FZF_CTRL_T_OPTS string empty Extra fzf options for CTRL-T. No
FZF_CTRL_R_OPTS string empty Extra fzf options for CTRL-R history widget. No
FZF_ALT_C_COMMAND shell command platform default Used by the ALT-C directory widget. Set to empty string to disable. No
FZF_ALT_C_OPTS string empty Extra fzf options for ALT-C. No
FZF_COMPLETION_TRIGGER string ** The trigger sequence for **-style fuzzy completion. No
FZF_COMPLETION_OPTS string empty Extra fzf options when invoked from a completion. No
FZF_COMPLETION_PATH_OPTS string empty Extra options for the path completion. No
FZF_COMPLETION_DIR_OPTS string empty Extra options for the directory completion. No
FZF_COMPLETION_PATH_COMMANDS shell list bash default list Override the list of commands that get path completion. No
FZF_COMPLETION_DIR_COMMANDS shell list cd pushd rmdir Override the list of commands that get directory completion. No
FZF_COMPLETION_VAR_COMMANDS shell list export unset printenv Override the list of commands that get variable completion. No
FZF_TMUX int (0/1) 0 If non-zero, route shell widgets through fzf-tmux. No
FZF_TMUX_HEIGHT size 40% Height for fzf-tmux and --tmux popup defaults. No
FZF_TMUX_OPTS string empty Extra options forwarded to fzf-tmux. No
FZF_PREVIEW_LINES int (set by fzf) Auto-set by fzf when running a preview command — the number of lines available in the preview window. No (set by fzf)
FZF_PREVIEW_COLUMNS int (set by fzf) Auto-set: columns available in the preview window. No (set by fzf)
FZF_PREVIEW_TOP / FZF_PREVIEW_LEFT int (set by fzf) Auto-set: top-row / left-column of the preview window. No (set by fzf)
FZF_PREVIEW_LABEL string (set by fzf) Auto-set: current preview label. No (set by fzf)
FZF_QUERY string (set by fzf) Auto-set: current query, available to commands invoked from execute/become/reload/transform. No (set by fzf)
FZF_PROMPT string (set by fzf) Auto-set: current prompt string. No (set by fzf)
FZF_POS int (set by fzf) Auto-set: 1-based cursor position in the result list. No (set by fzf)
FZF_KEY string (set by fzf) Auto-set: the key that triggered the action. No (set by fzf)
FZF_ACTION string (set by fzf) Auto-set: the name of the most recently executed action. No (set by fzf)
FZF_PORT int (set by fzf) Auto-set: TCP port the listen server is bound to. No (set by fzf)
FZF_INFO string (set by fzf) Auto-set: rendered info line text. No (set by fzf)
FZF_SELECT_COUNT int (set by fzf) Auto-set: number of items currently selected (multi-select). No (set by fzf)
FZF_TOTAL_COUNT int (set by fzf) Auto-set: total candidate count. No (set by fzf)
FZF_MATCH_COUNT int (set by fzf) Auto-set: count of matches for the current query. No (set by fzf)
FZF_LINES / FZF_COLUMNS int (set by fzf) Auto-set: dimensions of the fzf rendering area. No (set by fzf)
FZF_INPUT_STATE string (set by fzf) Auto-set: current state (enabled/disabled/hidden). No (set by fzf)
FZF_NTH string (set by fzf) Auto-set: current --nth spec. No (set by fzf)
FZF_CLICK_HEADER_LINE / FZF_CLICK_HEADER_COLUMN / FZF_CLICK_HEADER_NTH / FZF_CLICK_HEADER_WORD string (set on click-header) Auto-set: clicked field metadata. No (set by fzf)
FZF_CLICK_FOOTER_LINE / FZF_CLICK_FOOTER_COLUMN / FZF_CLICK_FOOTER_WORD string (set on click-footer) Auto-set: clicked footer field. No (set by fzf)
NO_COLOR flag unset If set (any value), fzf disables coloured output (no-color.org standard). No
RUNEWIDTH_EASTASIAN int unset If set, forces East-Asian width treatment for ambiguous-width characters. No
TERM string (from environment) Used by the renderer for terminfo-style capability detection. No
TMUX string (from environment) If set, fzf knows it is running inside tmux. No
ZELLIJ string (from environment) If set, fzf knows it is running inside Zellij. No
ESCDELAY int (ms) 100 Time fzf waits for a possible escape sequence after seeing a bare Esc. No
SLAB_KB int (KiB) (computed) Override the matcher slab size (advanced). No
BUF_KB int (KiB) 64 Override the reader buffer size (advanced). No
_FZF_CHILD_PROC flag (set by fzf) Internal: tells nested fzf invocations they are children. No (set by fzf)
TERM_PROGRAM, TERM_PROGRAM_VERSION, MSYS, ConEmuPID string (from environment) Read on Windows for terminal-host detection. No

Important

FZF_API_KEY is mandatory when --listen binds to anything other than localhost or a Unix socket. Without it, fzf returns FZF_API_KEY is required to allow remote access and exits. Generate one with openssl rand -hex 16.

3.2 Command-line flags — full reference

The following enumeration is grouped exactly as in fzf --help. Every flag has been verified against src/options.go's Usage constant.

Flag Type Default Description
-e, --exact bool off Enable exact-match.
+x, --no-extended bool off Disable extended-search mode.
-i, --ignore-case bool off Case-insensitive match.
+i, --no-ignore-case bool off Case-sensitive match.
--smart-case bool on Smart case (default — case-insensitive iff query is all lowercase).
--scheme=SCHEME enum default Scoring scheme: default, path, history.
-n, --nth=N[,..] spec empty Comma-separated field index expressions for limiting search scope.
--with-nth=N[,..] spec empty Transform the displayed line using field index expressions.
--accept-nth=N[,..] spec empty Define which fields to print on accept.
-d, --delimiter=STR regex AWK Field delimiter regex.
+s, --no-sort bool off Do not sort the result.
--literal bool off Do not normalise Latin-script letters.
--tail=NUM int unlimited Maximum number of items to keep in memory.
--disabled bool off Do not perform search (item count == result count).
--tiebreak=CRI[,..] enum-list length Up to 3 of: length, chunk, pathname, begin, end, index.

Input/Output

Flag Type Default Description
--read0 bool off Read input delimited by ASCII NUL.
--print0 bool off Print output delimited by ASCII NUL.
--ansi bool off Process ANSI colour codes in input.
--sync bool off Synchronous search for multi-staged filtering.

Global Style

Flag Type Default Description
--style=PRESET enum default Preset: default, minimal, full[:BORDER_STYLE].
--color=COLSPEC spec (terminal default) Base scheme `dark
--no-color bool off Disable colours.
--no-bold bool off Do not use bold text.

Display Mode

Flag Type Default Description
--height=[~][-]HEIGHT[%] size full screen Display fzf below the cursor with the given height. ~ auto-fits to input. Negative = terminal height minus value.
--min-height=HEIGHT[+] int 10+ Minimum height when --height is a percentage. + auto-grows.
--popup[=OPTS] / --tmux[=OPTS] spec center,50% Open in a tmux/Zellij popup. Format: [center|top|bottom|left|right][,SIZE[%]][,SIZE[%]][,border-native].

Layout

Flag Type Default Description
--layout=LAYOUT enum default One of default, reverse, reverse-list.
--margin=MARGIN spec 0 Outer margin. Format: TRBL / TB,RL / T,RL,B / T,R,B,L.
--padding=PADDING spec 0 Inner padding (same syntax).
--border[=STYLE] enum none Border style: rounded, sharp, bold, block, thinblock, double, horizontal, vertical, top, bottom, left, right, line, none.
--border-label=LABEL string empty Label printed on the outer border.
--border-label-pos=COL int / spec 0 (center) Border-label position; integer = column from left, negative = from right; :bottom switches to bottom border.

List Section

Flag Type Default Description
-m, --multi[=MAX] int off Enable multi-select with optional MAX cap.
--highlight-line bool off Highlight the whole current line.
--cycle bool off Cyclic scrolling.
--wrap[=MODE] enum char Line wrapping (char or word).
--wrap-sign=STR string ↳ Wrap-line indicator.
--no-multi-line bool off Disable multi-line display when reading with --read0.
--raw bool off Show non-matching items too.
--track bool off Track current selection across reloads.
--id-nth=N[,..] spec empty Identity fields for cross-reload tracking.
--tac bool off Reverse input order.
--gap[=N] int 1 Render N empty lines between items.
--gap-line[=STR] string ┈ / - Draw horizontal line on each gap.
--freeze-left=N / --freeze-right=N int 0 Number of fields to freeze on the corresponding edge.
--keep-right bool off Keep the right end of the line visible on overflow.
--scroll-off=LINES int 0 Lines to keep above/below when scrolling to the edge.
--no-hscroll bool off Disable horizontal scroll.
--hscroll-off=COLS int 10 Columns to keep to the right of the highlighted substring.
--jump-labels=CHARS string asdfghjklqwertyuiopzxcvbnm1234567890ASDFGHJKLQWERTYUIOPZXCVBNM… Label characters for jump mode.
--gutter=CHAR char ▌ Gutter column character.
--gutter-raw=CHAR char ▖ Gutter column character in --raw mode.
--pointer=STR string ▌ / > Pointer to the current line.
--marker=STR string ┃ / > Multi-select marker.
--marker-multi-line=STR string ╻┃╹ 3-element multi-line marker.
--ellipsis=STR string ·· Ellipsis for truncated lines.
--tabstop=SPACES int 8 Tab width.
--scrollbar[=C1[C2]] string │ / ┃ Scrollbar character(s) — first for list, second for preview.
--no-scrollbar bool off Hide the scrollbar.
--list-border[=STYLE] enum none Border around the list section (same vocabulary as --border).
--list-label=LABEL, --list-label-pos=COL spec empty / 0 Label for the list border.

Input Section

Flag Type Default Description
--no-input bool off Hide input/prompt section.
--prompt=STR string > Input prompt.
--info=STYLE enum default Info style: default, right, hidden, inline[-right][:PREFIX].
--info-command=COMMAND shell empty Command whose stdout becomes the info line.
--separator=STR string ─ / - Horizontal separator on info line.
--no-separator bool off Hide info-line separator.
--ghost=TEXT string empty Ghost text shown when query is empty.
--filepath-word bool off Word-wise movements respect path separators.
--input-border[=STYLE], --input-label=LABEL, --input-label-pos=COL spec none / empty / 0 Border and label for the input section.

Preview Window

Flag Type Default Description
--preview=COMMAND shell template empty Command to preview the current line.
--preview-window=OPT spec right:50% Layout. See User Guide §5.2 for full grammar (position, size, wrap, cycle, follow, info, hidden, border-STYLE, +SCROLL, ~HEADER_LINES, alt layout).
--preview-border[=STYLE] enum none Short for --preview-window=border-STYLE.
--preview-label=LABEL, --preview-label-pos=N spec empty / 0 Label for the preview border.
--preview-wrap-sign=STR string ↳ Wrap-line indicator inside the preview window.
Flag Type Default Description
--header=STR string empty Header line(s).
--header-lines=N int 0 Treat first N input lines as a fixed header.
--header-first bool off Print header before the prompt.
--header-border[=STYLE], --header-label=LABEL, --header-label-pos=COL spec none Border/label for the header section.
--header-lines-border[=STYLE] enum none Separate border for --header-lines content (pass none to separate without border).
Flag Type Default Description
--footer=STR string empty Footer line(s).
--footer-border[=STYLE], --footer-label=LABEL, --footer-label-pos=COL spec line / empty / 0 Border/label for the footer section.

Scripting

Flag Type Default Description
-q, --query=STR string empty Initial query.
-1, --select-1 bool off Auto-select if exactly one match.
-0, --exit-0 bool off Exit immediately if no match.
-f, --filter=STR string empty Print matches and exit (non-interactive).
--print-query bool off Print the query as the first output line.
--expect=KEYS csv empty Comma-separated keys that immediately accept and emit the key name.

Key/Event Binding

Flag Type Default Description
--bind=BINDINGS bind-spec (defaults) Custom key/event bindings. See Section 3.4 for the action catalog.

Advanced

Flag Type Default Description
--with-shell=STR shell prefix empty Shell command and flags used to start child processes (e.g. --with-shell='bash -c').
--listen[=[ADDR:]PORT] addr localhost:0 Start HTTP server. Use --listen-unsafe for non-local without API key (DANGEROUS).
--listen=SOCKET_PATH path empty Listen on a Unix socket (path must end in .sock).

Directory Traversal (when FZF_DEFAULT_COMMAND is unset)

Flag Type Default Description
--walker=OPTS csv file,follow,hidden Walker options: file, dir, follow, hidden.
--walker-root=DIR [...] paths . Roots to walk.
--walker-skip=DIRS csv .git,node_modules Directory names to skip.

History

Flag Type Default Description
--history=FILE path empty File for fzf's internal search history (NOT shell history).
--history-size=N int 1000 Maximum entries kept.

Shell Integration / Help

Flag Type Default Description
--bash bool off Print the embedded Bash integration script.
--zsh bool off Print the embedded Zsh integration script.
--fish bool off Print the embedded Fish integration script.
--version bool off Print version and exit.
--help, -h bool off Print usage and exit.
--man bool off Open the embedded man page (uses man if available, otherwise prints to stdout).

Profiling (build-tag pprof only)

Flag Type Description
--profile-cpu=FILE path Write a Go pprof CPU profile (build with go build -tags=pprof).
--profile-mem=FILE path Memory profile.
--profile-block=FILE path Block profile.
--profile-mutex=FILE path Mutex profile.

Warning

Profiling flags are gated behind the pprof build tag. Without that tag, fzf prints error: profiling not supported: FZF must be built with '-tags=pprof' to enable profiling.

3.3 Color groups

The --color value is a comma-separated list of group:fg[,bg][,attr] tuples. The recognised groups are:

Group Where it shows
fg / bg Default foreground / background
list-fg / list-bg List section
preview-fg / preview-bg Preview window
alt-bg Alternate row background (when set)
selected-fg / selected-bg / selected-hl Selected (multi) item
hl Highlighted match positions
pointer Current-line pointer
marker Multi-select marker
prompt Input prompt
input-bg / input-border / input-label Input section
header-bg / header-border / header-label Header section
footer-bg / footer-border / footer-label Footer section
info Info line
spinner Reader spinner
border Outer border
preview-border / preview-label / preview-scrollbar Preview chrome
list-border / list-label List chrome
separator Info-line separator
scrollbar Main scrollbar
gutter / alt-gutter Gutter column
gap-line Gap line between items
nth Nth-field highlight
label Default label
nomatch "No match" text
ghost Ghost-text colour
disabled Disabled-state colour

Attributes: regular, bold, dim, italic, underline, underline-double, underline-curly, underline-dotted, underline-dashed, blink, reverse, strikethrough, strip.

Foreground/background colours: named (black, red, …, white, bright-red, …, bright-white), 256-colour colour:N, or #RRGGBB truecolour.

3.4 Action catalog (full)

--bind accepts any of the actions below. Actions taking arguments use the form name(...) or name:STRING at the end of a chain. Multiple actions chain with +.

Cursor / line editing

beginning-of-line, end-of-line, forward-char, backward-char, forward-word, backward-word, forward-subword, backward-subword, backward-delete-char, backward-delete-char/eof, delete-char, delete-char/eof, kill-line, kill-word, kill-subword, backward-kill-word, backward-kill-subword, unix-line-discard (alias line-discard), unix-word-rubout (alias word-rubout), yank, clear-query.

Item movement

down, up, down-match, up-match, first (alias top), last, best, page-up, page-down, half-page-up, half-page-down, offset-up, offset-down, offset-middle, prev-history, next-history, prev-selected, next-selected.

Selection

select, deselect, select-all, deselect-all, clear-selection (alias clear-multi), toggle, toggle-down, toggle-up, toggle-in, toggle-out, toggle-all, change-multi, exclude, exclude-multi.

Search / pattern

enable-search, disable-search, toggle-search, enable-raw, disable-raw, toggle-raw, toggle-sort, track, track-current, untrack-current, toggle-track, toggle-track-current.

Acceptance / exit

accept, accept-non-empty, accept-or-print-query, print-query, abort, cancel, close, bg-cancel.

Preview

show-preview, hide-preview, toggle-preview, toggle-preview-wrap, toggle-preview-wrap-word, refresh-preview, preview-up, preview-down, preview-page-up, preview-page-down, preview-half-page-up, preview-half-page-down, preview-top, preview-bottom, change-preview(<COMMAND>), change-preview-window(<SPEC>), preview(<COMMAND>).

UI mutation (change-*)

change-prompt(<STR>), change-query(<STR>), change-header(<STR>), change-header-lines(<INT>), change-footer(<STR>), change-border-label(<STR>), change-list-label(<STR>), change-input-label(<STR>), change-header-label(<STR>), change-footer-label(<STR>), change-preview-label(<STR>), change-ghost(<STR>), change-pointer(<STR>), change-nth(<SPEC>), change-with-nth(<SPEC>), change-multi(<MAX>).

UI mutation (transform-*)

These run a shell command and use its stdout to set the corresponding field. Each has a bg- variant that runs in the background:

transform, transform-prompt, transform-query, transform-header, transform-header-lines, transform-footer, transform-border-label, transform-list-label, transform-input-label, transform-header-label, transform-footer-label, transform-preview-label, transform-ghost, transform-pointer, transform-nth, transform-with-nth, transform-search.

bg-transform, bg-transform-prompt, bg-transform-query, bg-transform-header, bg-transform-header-lines, bg-transform-footer, bg-transform-border-label, bg-transform-list-label, bg-transform-input-label, bg-transform-header-label, bg-transform-footer-label, bg-transform-preview-label, bg-transform-ghost, bg-transform-pointer, bg-transform-nth, bg-transform-with-nth, bg-transform-search.

Process management

execute(<COMMAND>), execute-silent(<COMMAND>), execute-multi(<COMMAND>), become(<COMMAND>), reload(<COMMAND>), reload-sync(<COMMAND>), put(<CHAR>), print(<STR>).

Visibility toggles

toggle-input, hide-input, show-input, toggle-header, show-header, hide-header, toggle-wrap, toggle-wrap-word, toggle-multi-line, toggle-hscroll.

Bind manipulation

unbind(<KEY>), rebind(<KEY>), toggle-bind(<KEY>).

pos(<INT>), search(<STR>), trigger(<EVENT>), replace-query, refresh-preview.

Misc

ignore, bell, clear-screen, jump, jump-accept.

Important

Action names are kebab-case and the parser is strict. Valid arguments for change-preview-window must satisfy the same grammar as --preview-window; bad input is rejected at parse time with invalid preview window option: <spec>.

3.5 Recognised key names

Keys for --bind triggers fall into the following categories:

  • ASCII printable characters: bare (a, ?, /).
  • Named keys: enter, tab, esc, space, bspace, del, home, end, pgup, pgdn, up, down, left, right, insert.
  • Function keys: f1–f24.
  • Modifiers: ctrl-X, alt-X, shift-X, ctrl-alt-X, ctrl-shift-X, alt-shift-X, ctrl-alt-shift-X (modifier order must be ctrl, alt, shift).
  • Mouse: left-click, right-click, shift-left-click, shift-right-click, double-click, scroll-up, scroll-down, shift-scroll-up, shift-scroll-down, preview-scroll-up, preview-scroll-down.
  • Special: ctrl-space, alt-space, ctrl-up, alt-up, shift-up, ctrl-alt-up, ctrl-shift-up, etc. (and equivalents for down/left/right/home/end/page-up/page-down/delete).

Events (used as triggers, fired by fzf)

change, start, load, focus, result, resize, one, zero, jump, jump-cancel, click-header, click-footer, multi, backward-eof.

3.6 Placeholder grammar (preview / execute / become / reload / transform)

Placeholder Description
{} Current line, shell-quoted.
{1}, {2}, {-1}, {-2} Single field by 1-based positive or negative index.
{1..3}, {2..}, {..-2} Field range.
{q} Current query.
{q:N}, {q:1..3} Query field (or range), split by --delimiter.
{n} 0-based item index.
{+} All currently selected items, space-separated.
{*} All currently matching items.
{f} Path to a temp file containing the current item.
{+f} Path to a temp file containing all selected items.
{r} Raw current line (no shell quoting).
{fzf:query} Shell-quoted current query (alternate form).
{fzf:action} Name of the most recent action.
{fzf:prompt} Current prompt.

The internal regex (from src/terminal.go): \\?(?:{[+*sfr]*[0-9,-.]*}|{q(?::s?[0-9,-.]+)?}|{fzf:(?:query|action|prompt)}|{[+*]?f?nf?}).

Important

Placeholders are templated through POSIX shell quoting unless {r} is used. Never wrap user-controlled strings in become(...) or --preview without {f} (or careful explicit quoting); shell injection is the natural attack surface.

3.7 Exit codes

Code Meaning
0 Selection accepted (or --filter produced output).
1 No match (input was non-empty).
2 Error — invalid options, broken pipe, terminal failure.
126 become(...) exec'd a command — this is the new program's exit-code domain, not fzf's.
130 User pressed Ctrl-C / Esc / SIGINT.

(Constants in src/constants.go: ExitOk, ExitNoMatch, ExitError, ExitBecome, ExitInterrupt.)

4. Deployment & Scaling

4.1 Single-machine deployment

The default deployment is "drop the binary on the box". No daemon, no config file, no PID file.

# /etc/profile.d/fzf.sh — system-wide integration
[ -x /usr/local/bin/fzf ] || return
case "$(basename "$SHELL")" in
  bash) eval "$(fzf --bash)" ;;
  zsh)  source <(fzf --zsh) ;;
  fish) fzf --fish | source ;;
esac

Tip

For NFS-mounted home directories, prefer the system-wide approach so the same fzf binary is used everywhere, and put FZF_DEFAULT_OPTS_FILE on the user's local disk (or set it from rc).

4.2 Tmux / Zellij popup

--tmux and --popup are aliases. Inside tmux ≥ 3.3 or Zellij ≥ 0.44, fzf detects the host and opens a popup with tmux display-popup (or the Zellij equivalent).

When tmux/Zellij are unavailable but you still want a contained UI, combine --height with --layout=reverse for an always-visible "split bottom" experience.

4.3 Performance tuning

Knob Default Effect
--threads N runtime.NumCPU() Number of matcher partitions. Lower for I/O-bound match commands; higher rarely helps past NumCPU.
--algo=v1 v2 Linear-time algorithm — faster on huge inputs (>1M lines), slightly less optimal scoring.
--no-extended / +x extended on Skip the term-set parser; treat the query as a single fuzzy term. Cheaper.
--literal normalised Skip Unicode normalisation.
--no-sort sort on Skip post-match sorting.
--tail=N unbounded Cap retained items. Crucial for tail -f-style streaming inputs.
BUF_KB env 64 Reader buffer size. Increase for streaming inputs with very long lines.
SLAB_KB env 200 Matcher slab size per partition.

Built-in performance constants (from src/constants.go):

Constant Value Notes
coordinatorDelayMax 100ms Maximum debounce window for screen redraws.
coordinatorDelayStep 10ms Adaptive backoff step.
readerBufferSize 64 KiB Default reader buffer.
readerSlabSize 128 KiB Reader slab.
readerPollInterval 10ms → 50ms Adaptive polling for streaming sources.
chunkSize 1024 Items per ChunkList node.
slab16Size 100 KiB Per-partition uint16 slab (≈ 12.8 MB total at 32 partitions).
slab32Size 2 KiB Per-partition int32 slab.
queryCacheMax 512 Max items in a cached query result.
mergerCacheMax 100 000 Max items in a cached merger.
previewDelayed 500ms Delay before showing "preview pending" indicator.
maxBgProcesses 30 Concurrent bg-transform / background commands.
maxBgProcessesPerAction 3 Per-action concurrency cap.
maxPatternLength 1000 Maximum query length.
maxMulti MaxInt32 Multi-select cap.

4.4 The --listen server

fzf --listen[=ADDR:PORT] runs a hand-rolled HTTP/1.1 server (defined in src/server.go) that accepts POST / with a body that is parsed the same way as a --bind action chain. Requests can also use GET /?limit=N&offset=M to fetch the current result set as JSON.

Authentication: when ADDR is anything other than localhost / a Unix socket, FZF_API_KEY must be set. The header X-API-Key is required on every request; the comparison is constant-time (crypto/subtle).

# Server side (e.g. an editor session)
export FZF_API_KEY=$(openssl rand -hex 16)
fzf --listen 127.0.0.1:6266 --listen-unsafe=false \
    --bind 'enter:become(${EDITOR} {})'

# Client side (any process)
curl -s -H "X-API-Key: $FZF_API_KEY" -X POST \
    --data 'change-query(linux)+reload(rg --files)' \
    http://127.0.0.1:6266/

# Read result set
curl -s -H "X-API-Key: $FZF_API_KEY" "http://127.0.0.1:6266/?limit=10&offset=0"

Constants: read deadline 10s, channel deadline 2s, max content-length 1 MiB. The server intentionally avoids net/http to keep the binary small (commented in src/server.go: --listen adds 0.5 MiB instead of the 2.9 MiB net/http would require).

Caution

--listen-unsafe skips the API-key check entirely. The server then accepts unauthenticated become/execute/reload actions from any network-reachable client — that is full remote command execution. Never enable on a multi-user host or any non-trusted network. The safest default is no --listen at all; the next safest is a Unix socket with chmod 0600 (which fzf does automatically).

4.5 Embedding fzf inside a script

The contract is: stdin is the candidate stream, stdout is the chosen line(s). Standard scripting patterns:

# Single-pick
chosen=$(some-source | fzf --height=40% --reverse) || exit
echo "you picked: $chosen"

# Multi-pick into an array (Bash)
mapfile -t chosen < <(some-source | fzf --multi --read0)

# Headless filter (no UI)
matches=$(echo -e "alpha\nbeta\ngamma" | fzf --filter=al)
echo "$matches"   # -> "alpha"

For non-interactive grep-style filtering, prefer --filter — it bypasses the TUI entirely and emits matches to stdout sorted by score.

5. Operations

5.1 Updating fzf

Method Update command
Homebrew brew upgrade fzf
apt sudo apt update && sudo apt upgrade fzf
dnf sudo dnf upgrade fzf
pacman sudo pacman -Syu fzf
Chocolatey choco upgrade fzf
Scoop scoop update fzf
Git clone cd ~/.fzf && git pull && ./install

After updating, regenerate the integration scripts (no-op if you use eval "$(fzf --bash)" rather than the legacy ~/.fzf.bash files).

5.2 Rolling back

If an upgrade breaks an existing binding:

  1. fzf --version to confirm the new release.
  2. Read the upstream CHANGELOG.md for breaking-change notes.
  3. Most package managers can pin the previous version (apt install fzf=<version>, brew install fzf@<version>, etc.).
  4. Or grab the previous release tarball from https://github.com/junegunn/fzf/releases and drop it on $PATH.

5.3 Logging / observability

fzf does not log to disk by default. For build-time profiling, the --profile-cpu/mem/block/mutex flags emit Go pprof files (requires -tags=pprof build).

For runtime tracing during development:

fzf --bench=2s   # internal benchmark mode (counts matches/sec)

--bench=DURATION is a developer-facing flag that runs an internal benchmark and prints results to stderr — handy when tuning --algo, --threads, --scheme.

5.4 Backup considerations

fzf is stateless except for:

Path Purpose Recovery
--history=FILE Per-instance fzf search history (NOT shell history). Plain text, one line per query.
FZF_DEFAULT_OPTS_FILE Default options. Plain text, version-controllable.

There is no cache directory, no lockfile, no PID file.

5.5 Health check

# Basic smoke test (use in deployment automation)
echo "hello" | timeout 5 fzf --filter=hello | grep -q hello && echo OK

--filter runs in headless mode, so it is safe in CI/CD scripts.

Note

--filter=STRING is the closest thing fzf has to a non-interactive health probe. It exits 0 on a match, 1 on no match, 2 on argument errors — making it directly usable in monitoring scripts.

5.6 Operations runbook

  • [x] Verify the binary on $PATH (which fzf)
  • [x] Verify the version (fzf --version)
  • [x] Smoke-test the integration (echo a | fzf --filter=a)
  • [ ] Source the integration script in your shell rc (eval "$(fzf --bash)")
  • [ ] Decide on FZF_DEFAULT_COMMAND and FZF_DEFAULT_OPTS
  • [ ] If using --listen, generate FZF_API_KEY and store it securely
  • [ ] If on macOS, install mawk or GNU awk for fastest history widget

6. Performance

6.1 Algorithm details

FuzzyMatchV2 (default) is a modified Smith-Waterman with bonuses for boundaries and consecutive matches. From src/algo/algo.go:

  • O(N×M) time, O(M) space (where N = haystack length, M = pattern length).
  • Bonuses: word boundary, consecutive match, capital-letter heads, separator transition.
  • Works on Unicode codepoints; uses uniseg for grapheme width.
  • Falls through to FuzzyMatchV1 when input exceeds heuristic limits (very long lines), preserving correctness with linear time.

FuzzyMatchV1 is a single-pass algorithm: O(N) time, no slab needed. Less optimal scoring but extremely fast on large inputs.

ExactMatchNaive, ExactMatchBoundary, PrefixMatch, SuffixMatch, EqualMatch: simple substring matchers; trigger ', 'word', ^, $, and ^word$ syntaxes respectively.

The SIMD-accelerated indexbyte2 (asm in src/algo/indexbyte2_amd64.s, indexbyte2_arm64.s, plus a portable Go fallback) finds the next byte in the haystack 2-5× faster than the standard library.

6.2 Memory model

The matcher uses a per-partition slab allocator (util.Slab) with two pools (slab16Size = 100 KiB of uint16, slab32Size = 2 KiB of int32). Each partition gets its own slabs to avoid contention.

The ChunkList is lock-free: append-only nodes of 1024 lines, each with its own ref count. The Reader, Matcher, and Terminal observe the list at different positions without synchronisation.

The ChunkCache keys query results by pattern hash (chunk-local). The cache is bounded — queryCacheMax = chunkSize / 2 = 512 — and discarded for patterns matching too many items.

6.3 Benchmarks (representative, x86_64 single core)

Input Default --algo=v1 --no-extended
100 K lines 50 ms / sub-pixel jitter 25 ms 30 ms
1 M lines 400 ms first match, 30 ms incremental 200 ms 250 ms
10 M lines 4 s first match, 200 ms incremental 2 s 2.5 s

(Numbers are illustrative; rerun --bench on your hardware to compare.)

Tip

If first-match latency on huge inputs matters, use --sync (waits for Reader to finish before showing the UI). For "see results as soon as possible", combine the default async mode with --no-sort to skip the final sort.

7. Security

7.1 Threat model

fzf is a client-side filter. The threat surface is:

  1. Shell injection through preview / execute / become / reload. Placeholders are POSIX-shell quoted by default. The {r} placeholder is raw — using it with untrusted input is unsafe.
  2. --listen HTTP/Unix-socket server. Without FZF_API_KEY, only localhost / Unix-socket bindings are allowed. --listen-unsafe removes the API-key check entirely; do not use on multi-user hosts.
  3. Malicious FZF_DEFAULT_COMMAND. fzf execs this verbatim. Audit it the way you audit $PROMPT_COMMAND or $LD_PRELOAD.

7.2 OpenBSD hardening

src/protector/protector_openbsd.go calls pledge("stdio rpath wpath cpath fattr proc exec tty") and unveil for the working directory. Other OSes are no-op (src/protector/protector.go).

7.3 The --listen API key

When the listen address is non-local, fzf demands FZF_API_KEY. The server compares the supplied X-API-Key header in constant time (crypto/subtle.ConstantTimeCompare). The unauthenticated path (socket already in use) → (error) is informational.

Caution

--listen-unsafe is a deliberate footgun. The codebase exposes it for single-user trusted environments only. Treat it the way you would treat xhost +: never on a shared host, never over the public network, never in a container that ships logs to a third party.

7.4 Embedded shell scripts

The integration scripts (shell/key-bindings.{bash,zsh,fish} and shell/completion.{bash,zsh,fish}) are embedded into the binary at build time via Go's //go:embed. They are emitted unmodified by fzf --bash / --zsh / --fish. Audit them once per release; the content is checked into the public repo so reproducible builds verify trivially.

7.5 No telemetry, no auto-update

fzf does not phone home, fetch update info, or open any network socket on startup. The only network code path is --listen, and it only opens when the user passes the flag. There is no auto-update; new releases come via your package manager.

7.6 Known security-relevant errors

Error When Mitigation
FZF_API_KEY is required to allow remote access --listen non-local without FZF_API_KEY. Set the env var, or bind to localhost / socket.
socket already in use: <path> Stale Unix socket. rm the path; verify ownership.
invalid api key (HTTP 401) Wrong X-API-Key. Check both client and server have the same value.
invalid become command become(...) parsed an empty / illegal command. Audit the binding template.

8. Developer Internals

8.1 Repository structure

.
├── main.go                  # entry point, embeds shell scripts + manpage
├── src/
│   ├── core.go              # Reader/Matcher/Terminal coordinator
│   ├── options.go           # The big options parser (~3900 lines)
│   ├── reader.go            # non-blocking source reader
│   ├── chunklist.go         # lock-free chunk list
│   ├── matcher.go           # parallel matcher (NumCPU partitions)
│   ├── pattern.go           # query parser (extended-search grammar)
│   ├── terminal.go          # UI loop + actions + preview (~17K lines)
│   ├── server.go            # hand-rolled HTTP server for --listen
│   ├── proxy.go             # become(...) exec helper
│   ├── tmux.go              # tmux popup launcher
│   ├── zellij.go            # Zellij popup launcher
│   ├── history.go           # internal search-history store
│   ├── ansi.go              # ANSI escape parser
│   ├── cache.go             # ChunkCache (per-pattern result cache)
│   ├── item.go              # Item struct + transform helpers
│   ├── result.go            # Result + sort criteria
│   ├── tokenizer.go         # field/range tokenizer (--nth / --with-nth)
│   ├── constants.go         # all the named timing/size constants
│   ├── functions.go         # misc helpers
│   ├── algo/
│   │   ├── algo.go          # FuzzyMatchV1/V2, Exact*, Prefix/Suffix/Equal
│   │   ├── normalize.go     # Latin-script normalisation
│   │   ├── indexbyte2_amd64.s   # SIMD accelerator (x86_64)
│   │   ├── indexbyte2_arm64.s   # SIMD accelerator (ARM64)
│   │   └── indexbyte2_other.go  # portable fallback
│   ├── tui/                 # rendering back-ends (LightRenderer, tcell)
│   ├── util/                # eventbox, slab, atomicbool, chars, etc.
│   └── protector/           # OpenBSD pledge/unveil
├── shell/
│   ├── common.sh            # helpers shared between integration scripts
│   ├── completion.{bash,zsh,fish}
│   ├── key-bindings.{bash,zsh,fish}
│   └── update.sh            # rebuilds the per-shell scripts from common.sh
├── plugin/
│   └── fzf.vim              # minimal Vim plugin (rich plugin is separate repo)
├── man/man1/
│   ├── fzf.1                # canonical man page
│   └── fzf-tmux.1
├── doc/fzf.txt              # vim-help format
├── test/                    # Ruby integration tests (minitest)
│   ├── runner.rb
│   ├── test_*.rb
│   ├── lib/{common.rb,common.sh,common.fish}
│   └── vim/fzf.vader
├── go.mod / go.sum / Makefile / .goreleaser.yml
├── install / install.ps1 / uninstall   # bootstrap / removal scripts
├── README.md / README-VIM.md / ADVANCED.md / BUILD.md / CHANGELOG.md / SECURITY.md
└── Dockerfile

8.2 Building from source

# Standard build
go build -o fzf .

# With profiling support
go build -tags=pprof -o fzf .

# Cross-compile (example: linux/arm64)
GOOS=linux GOARCH=arm64 go build -o fzf-linux-arm64 .

# Full release matrix (uses GoReleaser)
goreleaser release --clean --skip=publish --skip=sign --snapshot

The release ldflags strip and trim the binary:

-trimpath
-s -w -X main.version=<VER> -X main.revision=<COMMIT>

The Dockerfile builds an Alpine-based image with fzf in /usr/bin.

8.3 Code patterns and conventions

  • Goroutines + EventBox. Cross-component state changes are messages through util.EventBox rather than shared memory. New work that needs to communicate with the Terminal goes through this bus.
  • Slab allocators. Hot match paths use slab pools to avoid GC. New algorithms should follow the same pattern (see algo.FuzzyMatchV2 for the reference).
  • String-enum constants. Sort criteria, layouts, info styles, etc. are typed iota enums with *_string.go files generated by stringer. Never use string comparisons in hot paths.
  • Build tags for platform code. Look for //go:build ... constraints (e.g. terminal_unix.go, terminal_windows.go, proxy_unix.go/proxy_windows.go, result_x86.go/result_others.go).
  • Embedded assets. Shell integration and man page are embedded via //go:embed; updating them means recompiling. The shell/update.sh helper keeps the per-shell scripts in sync with common.sh.

8.4 Module map

Class / file Purpose LoC (approx)
Options (src/options.go:570) All parsed CLI options. The mother of all structs. (3900 LoC parser)
Reader (src/reader.go:21) Non-blocking input reader with adaptive polling. 200
ChunkList (src/chunklist.go:15) Lock-free append-only list of 1024-line chunks. 60
ChunkCache (src/cache.go:12) Per-pattern result cache. 80
Matcher (src/matcher.go:37) Parallel matcher; spawns N partitions. 350
Pattern (src/pattern.go:48) Compiled search query (term sets, AND-of-OR). 250
Item (src/item.go:17) One input line; supports nth/with-nth/transform. 200
Result (src/algo/algo.go:105) A scored match position. 50
Terminal (src/terminal.go:249) Event loop, layout, rendering, action dispatch, preview, history widget, jump mode, popup. (17 000 LoC)
Status / StatusItem (src/terminal.go:219) Per-item rendered status. 80
LightRenderer (src/tui/light.go:110) Hand-rolled xterm-style renderer. 1500
TcellWindow (src/tui/tcell.go:40) tcell-based renderer for Windows / legacy. 800
httpServer (src/server.go:40) --listen HTTP/1.1 server (no net/http). 180
History (src/history.go:10) Internal search-history file. 60

8.5 Testing strategy

Layer Tooling Path
Unit Go testing src/*_test.go, src/algo/*_test.go, src/tui/*_test.go, src/util/*_test.go
Integration minitest (Ruby) test/test_*.rb, runner: test/runner.rb
Vim plugin vader.vim test/vim/fzf.vader

Run unit tests:

go test ./...

Run integration tests (require a TTY emulator and tmux):

make test
# or
ruby test/runner.rb

Common test environment variables: TMUX, FZF_DEFAULT_COMMAND, FZF_DEFAULT_OPTS. The integration test framework drives a real fzf process inside tmux and asserts on the rendered output.

8.6 Contributing

  1. Read CHANGELOG.md and SECURITY.md from the repo root before opening a PR.
  2. Run gofmt -s -w . and go vet ./....
  3. Run shfmt -d shell/ for shell-script formatting.
  4. Run bundle exec rubocop for the Ruby tests.
  5. Add unit tests for any new algorithm or option; add integration tests for any new key/event/binding behaviour.
  6. Update man/man1/fzf.1 and the Usage constant in src/options.go in lock-step.

8.7 Potential improvements / known tech debt

  • The mega-terminal.go (17 000 LoC) handles event loop, rendering, and action dispatch in a single file. A split into event_loop.go, render.go, and actions.go would improve readability.
  • --listen-unsafe exists for backwards compatibility; an explicit deprecation timeline (with auto-localhost fallback) would reduce foot-gun surface.
  • The tcell back-end is the default on Windows; a native ConPTY renderer would reduce binary size and improve rendering speed on modern Windows Terminal.
  • The Ruby test suite is slow; porting the core integration tests to Go would simplify CI. (Acknowledged in BUILD.md.)

9. Integration Points

9.1 Shell integration

  • Bash / Zsh / Fish. Source the embedded scripts: eval "$(fzf --bash)", source <(fzf --zsh), fzf --fish | source. These provide CTRL-T, CTRL-R, ALT-C, and the ** completion trigger.
  • PowerShell / CMD. Use the community PSFzf module. Not officially supported in-tree.

9.2 Tmux

  • Popup mode. --tmux=center,80%,40% or --popup=.... Requires tmux 3.3+.
  • fzf-tmux wrapper. Separate shell script that ships with most packages. Provides finer-grained popup control on older tmux.

9.3 Zellij

  • Popup mode. --tmux works on Zellij ≥ 0.44 (the same flag branches at runtime).

9.4 Vim / Neovim

  • In-tree plugin. plugin/fzf.vim provides :FZF and core helpers.
  • Companion plugin. The richer plugin (:Files, :Buffers, :Rg, :Lines, etc.) is the separate junegunn/fzf.vim repository.
  • Embedding fzf in another plugin. Spawn fzf with vim.system or :! and parse stdout. The --expect=KEYS and --print-query flags produce well-defined output that's easy to parse.

9.5 Editors and IDEs

  • VS Code, IntelliJ. Community extensions wrap fzf as a quick-open back-end. Use --listen for low-latency repeated invocations.
  • Emacs. helm-fzf, consult-fzf, and similar packages.
  • Termux (Android). Same fzf binary; integrate via Termux's built-in shell integration.

9.6 The --listen HTTP / Unix-socket API

External processes drive fzf actions over HTTP:

POST /                              Body: action chain ("change-query(foo)+reload(...)")
GET  /?limit=N&offset=M             Returns JSON: {"items": [...], "selection": [...], "current": ...}

Headers: X-API-Key: <FZF_API_KEY> (mandatory when non-local). Content type: text/plain (request) / application/json (response). Max body length: 1 MiB. Read deadline: 10 s.

Note

The server is intentionally minimal — no net/http, no TLS, no session state. For TLS, front it with a reverse proxy such as caddy reverse_proxy localhost:6266 over a TLS-terminated listener.

9.7 Programmatic invocation patterns

Use case Pattern
Quick pick `result=$(some-source
Multi-pick `mapfile -t result < <(some-source
Headless filter `some-source
Two-step (query first, then act) `query=$(printf '\0'
Editor launcher fzf --bind 'enter:become(${EDITOR} {})'
Live grep (see User Guide §8.2 — --disabled + change:reload)