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

> Understand fzf execute vs execute-silent vs become actions. Learn how each command execution method impacts your fzf workflow and UI responsiveness.

- Repository: [Junegunn Choi/fzf](https://github.com/junegunn/fzf)
- Tags: internals
- Published: 2026-03-01

---

**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`](https://github.com/junegunn/fzf/blob/main/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`](https://github.com/junegunn/fzf/blob/main/src/actiontype_string.go) (lines 165-176): `actExecute`, `actExecuteSilent`, and `actBecome`.

The `doAction` closure in [`src/terminal.go`](https://github.com/junegunn/fzf/blob/main/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`](https://github.com/junegunn/fzf/blob/main/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.

```bash

# 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`](https://github.com/junegunn/fzf/blob/main/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.

```bash

# 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`](https://github.com/junegunn/fzf/blob/main/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.

```bash

# 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`](https://github.com/junegunn/fzf/blob/main/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`](https://github.com/junegunn/fzf/blob/main/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.