fzf execute vs execute-silent vs become: Command Execution Actions Explained

The execute action blocks the fzf UI and waits for the command to finish, execute-silent runs commands asynchronously in the background while keeping fzf interactive, and become replaces the fzf process entirely with the new command using execve-style process replacement.

When configuring key bindings in junegunn/fzf, understanding the difference between execute, execute-silent, and become actions is essential for building responsive terminal workflows. These three command execution actions handle process lifecycle and UI blocking differently, directly impacting how your terminal interface behaves when launching external programs.

How fzf Maps Action Keywords to Internal Types

fzf parses the right-hand side of a --bind expression in src/options.go (lines 18-84) using the isExecuteAction function. This logic maps the textual keywords "execute", "execute-silent", and "become" to internal action constants defined in src/actiontype_string.go (lines 165-176): actExecute, actExecuteSilent, and actBecome.

The doAction closure in src/terminal.go dispatches these actions to their respective handlers, determining whether the command runs in the foreground, background, or replaces the fzf process entirely.

execute: Blocking Foreground Command Execution

The execute action performs a synchronous, blocking command execution. When triggered, fzf calls t.executeCommand with background = false (found in src/terminal.go, lines 68-72).

During execution:

  • The fzf UI pauses and the terminal returns to "raw" mode
  • The command inherits fzf's stdin, stdout, and stderr
  • fzf waits for the command to exit before redrawing the interface
  • Control returns to fzf after the command completes

Use execute when you need user interaction with the launched program (such as viewing a file in less or editing in vim) and want fzf to wait until that interaction finishes.


# fzf waits for less to exit before returning to the interface

fzf --bind 'enter:execute:less {}'

execute-silent: Non-Blocking Background Execution

The execute-silent action performs an asynchronous, non-blocking command execution. fzf calls the same t.executeCommand function but passes background = true (src/terminal.go, lines 68-72).

During execution:

  • The command launches in a separate goroutine
  • fzf briefly blocks input for approximately 150ms (blockDuration) to prevent immediate keypresses from interfering
  • The UI immediately resumes accepting keystrokes
  • Command output is discarded unless explicitly redirected

Use execute-silent for fire-and-forget operations like opening a file in a GUI editor, sending a signal, or triggering a background script where you want fzf to remain interactive.


# vim opens in background; fzf stays interactive immediately

fzf --bind 'enter:execute-silent:vim {}'

become: Process Replacement with execve

The become action performs process replacement rather than subprocess execution. Instead of calling executeCommand, the actBecome handler in src/terminal.go (lines 27-44) builds the command string and either writes a proxy script (for tmux compatibility) or calls t.executor.Become.

Key characteristics:

  • fzf immediately closes its UI without pause or resume cycle
  • The fzf process is replaced by the target command using execve-style semantics
  • The new command inherits the terminal but fzf ceases to exist
  • No return to fzf is possible after become executes

Use become when you want fzf to act as a launcher that completely hands over control to another program, such as dropping into a shell at a selected directory or replacing fzf with an interactive file manager.


# fzf exits and is replaced by a new shell

fzf --bind 'enter:become:$SHELL'

# Open selected file in vim, replacing fzf entirely

fzf --bind 'enter:become:vim {}'

Summary

  • execute – Blocking foreground execution; fzf waits for the command to finish and returns to the interface
  • execute-silent – Non-blocking background execution; command runs in a goroutine while fzf remains interactive
  • become – Process replacement; fzf exits immediately and the new command takes over the terminal via execve

Frequently Asked Questions

Does execute-silent wait for the command to finish before returning to fzf?

No. The execute-silent action launches commands asynchronously in a background goroutine. According to the implementation in src/terminal.go, fzf only pauses input for approximately 150 milliseconds (blockDuration) before resuming normal operation, regardless of whether the command has completed.

Can I return to fzf after using the become action?

No. The become action performs an execve-style process replacement as implemented in src/executor.go. When become triggers, the fzf process image is completely replaced by the target command, meaning fzf ceases to exist and cannot be returned to without restarting the program.

Why does the terminal flicker when using execute but not execute-silent?

The execute action puts the terminal into raw mode and pauses the UI to allow the command to inherit stdin/stdout. This involves stopping the tcell rendering loop and restoring the terminal state, causing a visible flicker. In contrast, execute-silent keeps the UI active and only briefly blocks input, maintaining the fzf interface without interruption.

When should I use become instead of execute?

Use become when fzf should act as a launcher that completely hands over control to another application, such as dropping into a shell at a selected directory or opening a file manager. Use execute when you need to view or edit a single file and return to fzf afterward, such as previewing a file with less or editing with vim where you intend to resume browsing after closing the editor.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →