# Best Practices for Configuring fff.nvim: Complete Setup Guide

> Master fff.nvim configuration with best practices. Learn to set options, enable lazy sync, and optimize result ranking using frecency and history for efficient file navigation.

- Repository: [Dmitriy Kovalenko/fff.nvim](https://github.com/dmtrKovalenko/fff.nvim)
- Tags: best-practices
- Published: 2026-04-04

---

**Configure fff.nvim by setting options in the global table `vim.g.fff` before calling `setup()`, enable `lazy_sync` to defer file indexing until first use, and activate frecency and history databases for intelligent result ranking.**

*fff.nvim* is a high-performance fuzzy finder for Neovim powered by a Rust-based search engine. The plugin reads all user preferences from `vim.g.fff` and merges them with comprehensive defaults defined in [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua) (lines 89–136) during the initialization sequence. Understanding this configuration architecture ensures minimal startup overhead and a picker tailored to your workflow.

## Configuration Architecture

The plugin employs a two-phase initialization system designed for speed and flexibility.

### Global Configuration Merging

All runtime options are stored in `vim.g.fff` and merged with internal defaults using `vim.tbl_deep_extend('force', ...)` inside [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua). The `init()` function processes this table, applies deprecated-option migrations (such as rewriting legacy top-level `width` keys to `layout.width`), and caches the final configuration in a module-local state object. This approach allows you to define preferences in your [`init.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/init.lua) without side effects, as the plugin only reads the global variable during its initialization phase.

### Lazy Initialization

In [`plugin/fff.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/plugin/fff.lua) (lines 7–12), the plugin checks `vim.g.fff.lazy_sync` before spawning the Rust indexer. When set to `true` (the default), `require('fff.core').ensure_initialized()` is scheduled after `UIEnter`, deferring file indexing until you open your first picker. This keeps Neovim's startup time fast while ensuring the search backend is ready when needed.

## Essential Configuration Domains

### Base Path and UI Options

Define the search context and visual identity through top-level keys. Set `base_path = vim.fn.getcwd()` to ensure the picker always starts in your current project. Configure `prompt = '🪿 '` and `title = 'FFFiles'` to customize the window header, and adjust `max_results = 200` if you frequently work with large repositories and need deeper result sets.

### Layout and Window Management

The layout system in [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua) (lines 190–215) supports responsive sizing. Use `height = 0.8` and `width = 0.8` to occupy 80% of the screen estate, providing a comfortable view on most terminals. Set `preview_size = 0.5` and enable `flex = { size = 130, wrap = 'top' }` to automatically hide the preview panel when the terminal width drops below 130 columns. For file path display, `path_shorten_strategy = 'middle_number'` intelligently compresses long paths while preserving the project structure.

### Preview Settings

Prevent UI freezes by limiting `preview.max_size = 10 * 1024 * 1024` (10 MiB) for binary files. Enable line wrapping for documentation filetypes by setting `preview.filetypes = { markdown = { wrap_lines = true }, text = { wrap_lines = true } }`, improving readability of README files and logs without affecting code files.

### Grep Configuration

Live grep performance is controlled through the `grep` sub-table. Set `max_file_size = 10 * 1024 * 1024` and `max_matches_per_file = 100` to prevent the Rust engine from choking on minified assets. A `time_budget_ms = 150` ensures responsive results even on large codebases. Define `modes = { 'plain', 'regex', 'fuzzy' }` to cycle between literal string matching, regular expressions, and fuzzy finding during searches.

### Frecency and History Databases

Enable persistent scoring to improve result relevance over time. Set `frecency = { enabled = true }` to store usage data in `stdpath('cache')/fff_nvim`, boosting frequently opened files in the ranking algorithm. Activate `history = { enabled = true }` to save successful queries in `stdpath('data')/fff_queries`, enabling the "combo-boost" feature that favors files repeatedly opened with similar queries.

### Git Integration

Control visual noise with `git.status_text_color = false` (default) to keep filenames neutral, or enable it to colorize text based on git status. The plugin uses highlight groups such as `FFFGitModified` and `FFFGitUntracked` defined in the default configuration, which you can remap to your color scheme's groups.

### Debugging Options

Keep `debug.enabled = false` for daily use to avoid performance overhead. Enable `debug.show_scores = true` temporarily when tuning scoring algorithms to visualize why certain files rank higher. Access this toggle at runtime via `require('fff.conf').toggle_debug()` or the `:FFFDebug toggle` command.

## Complete Configuration Examples

### Minimal Future-Proof Setup

Place this in your [`init.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/init.lua) before the plugin loads to ensure all preferences are captured during the initialization phase in [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua):

```lua
-- ~/.config/nvim/init.lua
vim.g.fff = {
  -- Search context
  base_path = vim.fn.getcwd(),
  prompt    = '🪿 ',
  title     = 'FFFiles',
  max_results = 200,

  -- Responsive layout
  layout = {
    height = 0.85,
    width  = 0.85,
    preview_position = 'right',
    preview_size = 0.45,
    flex = { size = 120, wrap = 'top' },
    path_shorten_strategy = 'middle_number',
  },

  -- Preview handling
  preview = {
    enabled = true,
    max_size = 5 * 1024 * 1024,   -- 5 MiB limit
    binary_file_threshold = 0,    -- Treat all files as text
    filetypes = {
      markdown = { wrap_lines = true },
      text     = { wrap_lines = true },
    },
  },

  -- Grep performance tuning
  grep = {
    max_file_size = 8 * 1024 * 1024,
    time_budget_ms = 100,
    modes = { 'plain', 'regex', 'fuzzy' },
  },

  -- Smart ranking databases
  frecency = { enabled = true },
  history   = { enabled = true },

  -- Git visuals
  git = { status_text_color = false },

  -- Diagnostics
  debug = { enabled = false, show_scores = false },
}

require('fff').setup(vim.g.fff)

```

### Per-Picker Overrides

Override specific options for individual commands without touching the global configuration:

```lua
-- Quick grep with only regex and plain modes
vim.keymap.set('n', '<leader>sg', function()
  require('fff').live_grep({
    query = vim.fn.expand("<cword>"),
    grep = { modes = { 'regex', 'plain' } },
  })
end, { desc = 'Search word with regex-fallback' })

```

This demonstrates that `live_grep()` accepts a `grep` sub-table, letting you tailor the search mode list for specific workflows while keeping your default configuration intact.

### Custom Highlight Groups

Map git status colors to your color scheme for consistent theming:

```lua
-- Define custom highlights
vim.api.nvim_set_hl(0, 'CustomGitModified', { fg = '#ff8800' })
vim.api.nvim_set_hl(0, 'CustomGitUntracked', { fg = '#00ff88' })

vim.g.fff = {
  git = { status_text_color = true },
  hl = {
    git_modified = 'CustomGitModified',
    git_untracked = 'CustomGitUntracked',
  },
}
require('fff').setup(vim.g.fff)

```

This configuration binds the plugin's default highlight group names (defined in [`doc/fff.nvim.txt`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/doc/fff.nvim.txt) lines 90–120) to your custom color definitions, ensuring the picker respects your terminal's aesthetic.

## Summary

- **Initialize early**: Set `vim.g.fff` before calling `setup()` to ensure [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua) captures your preferences during the merge phase.
- **Defer indexing**: Keep `lazy_sync = true` (the default in [`plugin/fff.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/plugin/fff.lua)) to prevent startup delays by scheduling the Rust indexer after `UIEnter`.
- **Enable smart ranking**: Turn on `frecency` and `history` databases to improve result relevance based on your editing patterns.
- **Limit resource usage**: Cap `preview.max_size` and `grep.max_file_size` at 5–10 MiB to prevent UI freezes on large binary files.
- **Use flex layouts**: Configure `layout.flex` to automatically adapt the preview panel width based on terminal size.
- **Debug sparingly**: Enable `debug.show_scores` only when tuning algorithms, and use `toggle_debug()` for runtime inspection without configuration changes.

## Frequently Asked Questions

### How do I migrate deprecated configuration options in fff.nvim?

The configuration loader in [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua) automatically migrates legacy keys using an internal migration table. For example, top-level `width` and `height` keys are automatically rewritten to `layout.width` and `layout.height` with a deprecation warning via `vim.notify`. To avoid these warnings, update your configuration to use the current nested structure under `layout` and `preview` sub-tables as documented in the default configuration (lines 89–136).

### Why should I enable lazy_sync in fff.nvim?

Setting `lazy_sync = true` (the default) in `vim.g.fff` defers the execution of `require('fff.core').ensure_initialized()` until after Neovim's `UIEnter` event, as implemented in [`plugin/fff.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/plugin/fff.lua) (lines 7–12). This prevents the Rust file indexer from blocking your editor during startup, ensuring immediate responsiveness when opening Neovim while maintaining fast picker performance once the index is built in the background.

### How do I customize git status colors in fff.nvim?

Map the plugin's highlight group names to your color scheme after calling `setup()`. The default groups `FFFGitModified`, `FFFGitUntracked`, and others are documented in [`doc/fff.nvim.txt`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/doc/fff.nvim.txt) (lines 90–120). Set `git.status_text_color = true` in your configuration, then use `vim.api.nvim_set_hl` to link these groups to your preferred colors, or override the group names entirely in the `hl` configuration table to point to custom highlight groups you define.

### What is the recommended way to debug scoring algorithms in fff.nvim?

Enable runtime inspection by calling `require('fff.conf').toggle_debug()`, which flips the `debug.show_scores` boolean and emits a notification. This overlays relevance scores directly in the picker UI, allowing you to see why the Rust ranking algorithm prioritizes certain files. For file-based diagnostics, ensure `logging.enabled = true` and `log_level = 'info'` are set to capture detailed indexer behavior in Neovim's log files without impacting interactive performance.