How to Customize fff.nvim with Lua: Complete Configuration Guide
Yes, fff.nvim is fully customizable through Lua by calling require('fff').setup() to override defaults defined in lua/fff/conf.lua, with your settings stored in the global variable vim.g.fff and automatically merged with built-in defaults at runtime.
fff.nvim is a high-performance file finder for Neovim that combines a Rust backend with a comprehensive Lua configuration layer. Unlike plugins with rigid settings, fff.nvim exposes every behavior—from window geometry to keybindings and grep modes—through plain Lua tables that take effect immediately when the picker opens.
Understanding the Configuration Architecture
The plugin organizes customization into three distinct layers that work together at runtime.
The Configuration layer in lua/fff/conf.lua defines the default schema, validation logic, and the get() function that merges user settings. The Core logic in lua/fff/core.lua initializes the Rust backend (fff.fuzzy) and manages global autocmds. The Public API in lua/fff/main.lua exposes user-facing functions like setup(), find_files(), and live_grep() that consume your configuration.
When you call require('fff').setup(user_config), the table is stored in vim.g.fff (line 90 of lua/fff/conf.lua). Each time the picker launches, require('fff.conf').get() merges your overrides with the comprehensive default table (lines 89-336 of conf.lua), handling deprecated fields with migration warnings (lines 55-73) before the UI renders.
Customizing Layout and Appearance
The layout section controls the floating window geometry and visual behavior.
You can set layout.height and layout.width as ratios (0.0 to 1.0), position the preview pane using layout.preview_position ('left', 'right', 'top', 'bottom'), and choose how paths are truncated with layout.path_shorten_strategy ('beginning', 'end', or 'none'). To disable the scrollbar, set layout.show_scrollbar = false.
Configuring the Preview Pane
Preview settings live under the preview key and support filetype-specific overrides.
Set preview.enabled = false to disable previews entirely, or limit resource usage with preview.max_size (default is 5 MiB). Enable soft wrapping with preview.wrap_lines, and configure per-filetype behavior using preview.filetypes.markdown.wrap_lines or preview.filetypes.json.wrap_lines.
Remapping Keys in Lua
The keymaps table accepts single strings or lists of strings for multiple bindings.
Available actions include close, select, move_up, move_down, toggle_debug, focus_preview, and cycle_grep_modes. For example:
keymaps = {
close = '<C-c>',
select = '<CR>',
move_up = { 'k', '<Up>', '<C-p>' },
toggle_debug = '<F5>',
}
Grep and Search Configuration
Under the grep section, you define available search modes and indexing limits.
Set grep.modes = { 'plain', 'regex', 'fuzzy' } to control which modes cycle when triggering the cycle_grep_modes action. Adjust grep.max_file_size to skip large files during indexing, and enable grep.smart_case for case-insensitive matching unless uppercase letters are present.
Runtime API for Dynamic Customization
Beyond static setup, fff.nvim exposes functions for live configuration changes without restarting Neovim.
require('fff').toggle_debug() flips the debug.show_scores flag to display ranking calculations in the UI (implemented in lua/fff/conf.lua lines 54-61).
require('fff').change_indexing_directory(new_path) updates the search root immediately (see lua/fff/main.lua lines 78-85). This is useful for switching to a git repository root or project subdirectory on the fly.
require('fff').scan_files() forces a rescan of the current workspace index (lines 58-63 of main.lua).
Complete Setup Example
Here is a comprehensive configuration that overrides layout, keymaps, preview settings, and grep modes:
require('fff').setup({
layout = {
height = 0.9,
width = 0.7,
preview_position = 'right',
preview_size = 0.4,
path_shorten_strategy = 'end',
show_scrollbar = false,
},
keymaps = {
close = '<C-c>',
select = '<CR>',
move_up = { 'k', '<Up>' },
move_down = { 'j', '<Down>' },
toggle_debug = '<F5>',
focus_preview = '<Leader>p',
},
preview = {
enabled = true,
max_size = 5 * 1024 * 1024, -- 5 MiB
wrap_lines = true,
filetypes = {
markdown = { wrap_lines = true },
json = { wrap_lines = true },
},
},
grep = {
modes = { 'plain', 'regex', 'fuzzy' },
max_file_size = 20 * 1024 * 1024, -- 20 MiB
smart_case = true,
},
frecency = {
enabled = true,
min_combo_count = 10,
},
logging = {
enabled = true,
log_level = 'debug',
},
})
To change the indexing root at runtime:
local git_root = vim.fn.systemlist('git rev-parse --show-toplevel')[1]
if git_root ~= '' then
require('fff').change_indexing_directory(git_root)
vim.notify('FFF now indexing from: ' .. git_root)
end
Summary
- fff.nvim stores user configuration in
vim.g.fffviarequire('fff').setup()and merges it with defaults fromlua/fff/conf.luaat runtime - Customize layout dimensions, preview behavior, keymaps, grep modes, frecency history, and logging through nested Lua tables
- Runtime functions like
toggle_debug()andchange_indexing_directory()allow dynamic adjustments without restarting Neovim - The UI queries configuration fresh each time it opens, so changes to
vim.g.fffor calls tosetup()take effect immediately
Frequently Asked Questions
Can I customize fff.nvim keybindings in Lua?
Yes. Pass a keymaps table to require('fff').setup() with keys like close, select, move_up, and toggle_debug. Each value can be a single string or a list of strings to bind multiple keys to the same action, such as move_up = { 'k', '<Up>' }.
Where does fff.nvim store its default configuration?
Default values are defined in lua/fff/conf.lua (lines 89-336). This file also contains the get() function that merges your vim.g.fff settings with these defaults, and handles deprecated field migrations (lines 55-73).
Can I change the file search directory without restarting Neovim?
Yes. Call require('fff').change_indexing_directory('/new/path') at any time. This function updates the Rust backend's indexing root immediately without requiring a restart, as implemented in lua/fff/main.lua lines 78-85.
How do I enable debug mode to see search scores?
Use require('fff').toggle_debug() or map it to a key like <F5>. This modifies the debug.show_scores flag in the active configuration (lines 54-61 of conf.lua) and prints a confirmation message when enabled.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →