# How to Use fzf as an Interactive Selector for ripgrep: Complete Integration Guide

> Integrate fzf with ripgrep for interactive file searching. Learn how to use fzf's reload action to trigger ripgrep on keystrokes and open results directly in your editor.

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

---

**Use fzf's `--bind` option with the `reload` action attached to the `change` event to trigger ripgrep on every keystroke, disable fzf's internal filtering with `--disabled`, and parse ripgrep's file:line:column output to open selections directly in your editor.**

The `junegunn/fzf` repository provides a general-purpose command-line fuzzy finder that functions as a powerful interactive selector for ripgrep. By leveraging fzf's event-action engine, you can build a live search interface where ripgrep executes on every query change, returning structured results that fzf displays while preserving syntax highlighting and exact positional information.

## Understanding the fzf Event-Action Engine

### The reload Action and change Event

According to the source code in [`src/options.go`](https://github.com/junegunn/fzf/blob/main/src/options.go), fzf parses the `reload` keyword as part of its action regex system. When you bind `reload` to the `change` event, fzf creates a `searchRequest` that is queued in [`src/terminal.go`](https://github.com/junegunn/fzf/blob/main/src/terminal.go) (lines 7477-7490). This request executes your ripgrep command as an external process and streams its output back into fzf's item list without blocking the user interface.

### Disabling Internal Filtering

The `--disabled` flag is critical for ripgrep integration. It prevents fzf from applying its fuzzy matching algorithm to the incoming data, ensuring that ripgrep remains the sole source of search results and filtering logic. This transforms fzf from a fuzzy finder into a pure interactive selector for ripgrep's output.

## Implementing the ripgrep-fzf Workflow

### Basic Configuration with reload Binding

Start fzf with bindings that trigger ripgrep when the query changes. The `{q}` placeholder expands to the current query string, while `{1}` and `{2}` capture the file path and line number from ripgrep's colon-delimited output:

```bash
: | rg_prefix='rg --column --line-number --no-heading --color=always --smart-case' \
    fzf --bind 'start:reload:$rg_prefix ""' \
        --bind 'change:reload:$rg_prefix {q} || true' \
        --bind 'enter:become(vim {1} +{2})' \
        --ansi --disabled \
        --height=50% --layout=reverse

```

### Adding Preview and Debouncing

For a richer interface, add a preview window showing the file content and debounce rapid keystrokes to prevent spawning excessive ripgrep processes:

```bash
RG='rg --column --line-number --no-heading --color=always --smart-case'
fzf --ansi --disabled --height=50% --layout=reverse \
    --bind "start:reload:$RG ''" \
    --bind "change:reload:sleep 0.1; $RG {q} || true" \
    --bind "enter:become(vim {1} +{2})" \
    --preview 'bat --style=numbers --color=always --highlight-line {2} {1}' \
    --preview-window 'right:70%,border-left'

```

The `sleep 0.1` command waits 100 milliseconds after the last keystroke before executing the reload, reducing CPU load during rapid typing.

### Toggling Between ripgrep and fzf Filtering

Switch between ripgrep mode and fuzzy filtering mid-session to refine results after an initial search:

```bash
RG='rg --column --line-number --no-heading --color=always --smart-case '
fzf --ansi --disabled \
    --bind "start:reload:$RG {q}" \
    --bind "change:reload:sleep 0.1; $RG {q} || true" \
    --bind "alt-enter:unbind(change)+change-prompt('2. fzf> ')+enable-search+clear-query" \
    --bind "enter:become(vim {1} +{2})" \
    --prompt '1. ripgrep> ' \
    --preview 'bat --color=always {1} --highlight-line {2}'

```

Pressing `Alt+Enter` unbinds the change event, enables fzf's native fuzzy search, and switches the prompt, allowing you to filter the existing ripgrep results without re-executing the search.

## How the Reload Mechanism Works Internally

According to the `junegunn/fzf` source code, the reload integration relies on two core components:

- **[`src/options.go`](https://github.com/junegunn/fzf/blob/main/src/options.go)** – Parses the `reload` and `reload-sync` action keywords when processing `--bind` expressions. The parser recognizes these as valid actions that can be attached to events like `change`, `start`, or key combinations.

- **[`src/terminal.go`](https://github.com/junegunn/fzf/blob/main/src/terminal.go)** (lines 7477-7490) – When a reload action triggers, the terminal controller builds a `searchRequest` containing the external command. This request enters the search queue, executing the ripgrep process and streaming its output back into fzf's item list without blocking the UI.

The `--ansi` flag ensures that ripgrep's color escape sequences pass through to the terminal, while `--disabled` bypasses fzf's internal matcher entirely, delegating all filtering logic to the external command.

## Summary

- **Bind `reload` to `change`** – Use `--bind 'change:reload:rg ...'` to execute ripgrep on every keystroke.
- **Disable fuzzy filtering** – Add `--disabled` to let ripgrep control the matching logic exclusively.
- **Preserve colors** – Include `--ansi` to display ripgrep's syntax highlighting within fzf.
- **Handle selection** – Use `enter:become(vim {1} +{2})` to open files at specific lines and columns.
- **Debounce input** – Prefix reload commands with `sleep 0.1` to reduce process spam during rapid typing.
- **Toggle modes** – Use `unbind(change)` and `enable-search` to switch between ripgrep and fzf filtering.

## Frequently Asked Questions

### How do I prevent fzf from filtering ripgrep results?

Pass the `--disabled` flag when starting fzf. This disables fzf's internal fuzzy matcher, ensuring that ripgrep remains the sole source of search results and filtering logic. Without this flag, fzf would apply its fuzzy algorithm to ripgrep's output, potentially hiding relevant matches.

### What is the purpose of the reload action in fzf?

The `reload` action, parsed in [`src/options.go`](https://github.com/junegunn/fzf/blob/main/src/options.go) and executed via `searchRequest` in [`src/terminal.go`](https://github.com/junegunn/fzf/blob/main/src/terminal.go), tells fzf to replace its current item list with the output of an external command. When bound to the `change` event, it enables live updating of results as the user types, creating a responsive search interface.

### How can I add a file preview when using fzf with ripgrep?

Add the `--preview` flag with a command that accepts fzf's placeholders. For example: `--preview 'bat --style=numbers --color=always --highlight-line {2} {1}'`. The `{1}` and `{2}` placeholders extract the file path and line number from ripgrep's colon-delimited output, allowing the preview to highlight the specific match line.

### Why does my ripgrep integration feel slow when typing?

Rapid keystrokes spawn multiple ripgrep processes simultaneously, overwhelming the CPU. Add a debounce delay by prefixing the reload command with `sleep`: `--bind 'change:reload:sleep 0.1; rg ...'`. This waits 100 milliseconds after the last keystroke before executing ripgrep, reducing process spam and improving responsiveness.