Best Practices for Configuring fff.nvim: Complete Setup Guide

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 (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. 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 without side effects, as the plugin only reads the global variable during its initialization phase.

Lazy Initialization

In 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 (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 before the plugin loads to ensure all preferences are captured during the initialization phase in lua/fff/conf.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:

-- 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:

-- 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 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 captures your preferences during the merge phase.
  • Defer indexing: Keep lazy_sync = true (the default in 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 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 (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 (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.

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.

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 →