# How to Customize fff.nvim with Lua: Complete Configuration Guide

> Customize fff.nvim with Lua using require('fff').setup() to override defaults. Learn how to configure this file finder easily with our complete guide.

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

---

**Yes, fff.nvim is fully customizable through Lua by calling `require('fff').setup()` to override defaults defined in [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/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`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/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`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/core.lua) initializes the Rust backend (`fff.fuzzy`) and manages global autocmds. The **Public API** in [`lua/fff/main.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/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`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/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`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/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:

```lua
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`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua) lines 54-61).

**`require('fff').change_indexing_directory(new_path)`** updates the search root immediately (see [`lua/fff/main.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/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`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/main.lua)).

## Complete Setup Example

Here is a comprehensive configuration that overrides layout, keymaps, preview settings, and grep modes:

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

```lua
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.fff` via `require('fff').setup()` and merges it with defaults from [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua) at runtime
- Customize **layout** dimensions, **preview** behavior, **keymaps**, **grep** modes, **frecency** history, and **logging** through nested Lua tables
- Runtime functions like `toggle_debug()` and `change_indexing_directory()` allow dynamic adjustments without restarting Neovim
- The UI queries configuration fresh each time it opens, so changes to `vim.g.fff` or calls to `setup()` 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`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/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`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/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`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/conf.lua)) and prints a confirmation message when enabled.