# fff.nvim Custom Configuration: Complete Guide to Setup Options

> Master fff.nvim custom configurations with this complete guide. Learn to personalize UI layout keymaps preview behavior and more via vim.g.fff or require('fff').setup().

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

---

**Yes, fff.nvim supports extensive custom configurations through `vim.g.fff` or `require('fff').setup()`, allowing you to customize UI layout, keymaps, preview behavior, git integration, and search algorithms.**

fff.nvim is a fast fuzzy finder plugin for Neovim built around a flexible configuration system. The plugin reads user preferences from a global variable or setup function and merges them with comprehensive defaults defined in [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua). Whether you need to adjust the window layout, disable previews, or configure grep modes, every aspect of the plugin can be tailored to your workflow.

## Configuration Architecture

Understanding how fff.nvim processes configuration helps you decide between setup methods and troubleshoot issues.

### Configuration Sources

The plugin supports two primary methods for supplying custom settings. When the plugin first needs its configuration, [`fff.conf`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/fff.conf) checks `vim.g.fff` at line 89 in [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua):

```lua
local config = vim.g.fff or {}

```

If you call `require('fff').setup({ ... })`, the function stores your table directly in `vim.g.fff` at line 45 of the same file. This design ensures compatibility with any plugin manager, as the configuration persists in a global variable accessible throughout the session.

### Default Values and Merging

A complete set of defaults resides in `default_config` (lines 92-135 of [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua)). This table defines base paths, prompt strings, layout dimensions, keymaps, highlight groups, frecency settings, git integration, debug flags, and logging options.

When `conf:get()` executes, it merges user settings with defaults using:

```lua
vim.tbl_deep_extend('force', default_config, migrated_user_config)

```

This deep merge at lines 39-40 ensures your overrides take precedence while preserving unspecified defaults.

### Deprecation Handling

The plugin automatically migrates old option names to new schemas. The `handle_deprecated_config()` function (lines 58-73 of [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua)) processes legacy keys like `width` (migrated to `layout.width`) and emits warnings via `vim.notify` when it detects deprecated usage.

### Lazy Initialization

Configuration loading is deferred until the `UIEnter` event, as implemented in [`plugin/fff.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/plugin/fff.lua) (lines 7-12). During initialization, `require('fff.core').ensure_initialized()` accesses the merged configuration. You can disable this lazy loading by setting `lazy_sync = false` in your configuration.

## How to Configure fff.nvim

You can supply configuration before or after the plugin loads, depending on your preference and plugin manager setup.

### Using setup()

The most common approach calls the setup function in your Neovim configuration:

```lua
require('fff').setup({
  base_path = vim.fn.expand('~/projects'),
  prompt = '🔎 ',
  layout = {
    height = 0.9,
    width = 0.7,
    preview_position = 'bottom',
    preview_size = 0.4,
    show_scrollbar = false,
  },
  keymaps = {
    close = 'q',
    select = '<CR>',
    toggle_debug = '<F5>',
    cycle_grep_modes = '<C-Tab>',
  },
  git = { status_text_color = true },
  debug = { enabled = true, show_scores = true },
})

```

### Using vim.g.fff

For users who prefer global variables or need configuration available before the plugin loads:

```lua
vim.g.fff = {
  lazy_sync = false,
  max_results = 200,
  grep = {
    modes = { 'plain', 'regex' },
    smart_case = false,
  },
}

```

Because [`conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/conf.lua) reads `vim.g.fff` on first demand, this table is respected even if you never explicitly call `setup()`.

### Runtime Configuration Changes

The configuration object remains mutable after load. Access the active configuration table and modify specific values:

```lua
local cfg = require('fff.conf').get()
cfg.layout.preview_position = 'left'
cfg.keymaps.toggle_select = '<Space>'

```

Debug scores can also be toggled on the fly using the `:FFFDebug` command, which manipulates `require('fff.conf').get().debug.show_scores`.

## Configuration Examples

### Customizing UI Layout

Control the finder window dimensions and preview placement:

```lua
require('fff').setup({
  layout = {
    height = 0.8,
    width = 0.6,
    preview_position = 'right',
    preview_size = 0.5,
  },
})

```

### Disabling Preview

To save screen real estate, completely disable the preview pane:

```lua
require('fff').setup({
  preview = { enabled = false },
})

```

The UI will render only the file list without the preview panel.

### Grep Mode Configuration

Customize how the grep functionality behaves across different search modes:

```lua
vim.g.fff = {
  grep = {
    modes = { 'plain', 'regex', 'fuzzy' },
    smart_case = true,
    max_results = 100,
  },
}

```

## Key Source Files

Reference these files when diving deeper into fff.nvim custom configuration:

- **[`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua)** – Core configuration handling including defaults, merging logic, deprecation migration, and the public `setup()`/`get()` API
- **[`plugin/fff.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/plugin/fff.lua)** – Lazy-loading bootstrap that determines when configuration is first consulted
- **[`lua/fff/main.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/main.lua)** – Public module interface that forwards calls to core logic
- **[`lua/fff/picker_ui.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/picker_ui.lua)** – UI layout implementation that respects the `layout` and `preview` configuration tables
- **[`lua/fff/file_picker/icons.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/file_picker/icons.lua)** – Icon handling that detects providers based on configuration settings

## Summary

- **fff.nvim custom configuration** is handled through `vim.g.fff` or `require('fff').setup()`, with both methods storing values in a global variable that merges with defaults
- The configuration system in [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua) uses `vim.tbl_deep_extend` to combine user settings with comprehensive defaults covering UI, keymaps, git, and search behavior
- Deprecated options are automatically migrated via `handle_deprecated_config()` with user notifications
- Configuration supports runtime modification by accessing `require('fff.conf').get()`
- Lazy initialization defers configuration loading until `UIEnter` unless `lazy_sync` is disabled

## Frequently Asked Questions

### How do I configure fff.nvim without calling setup()?

Set the `vim.g.fff` global variable before the plugin initializes. Because [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua) reads this variable at line 89 when first accessed, your settings will apply even without an explicit `setup()` call. This approach works with any plugin manager and ensures configuration is available during the lazy-loading phase.

### Can I change configuration options after fff.nvim has loaded?

Yes. The configuration table returned by `require('fff.conf').get()` remains mutable after initialization. You can modify values like `layout.preview_position` or `keymaps.toggle_select` at runtime, and they will affect subsequent picker windows. Debug settings specifically can be toggled using the `:FFFDebug` command.

### Where are the default configuration values defined?

Default values are defined in the `default_config` table at lines 92-135 of [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua). This comprehensive table includes settings for base paths, prompts, window dimensions, keymaps, highlight groups, frecency databases, git integration, and logging options. These defaults are merged with your custom configuration using `vim.tbl_deep_extend`.

### How does fff.nvim handle deprecated configuration options?

The plugin includes a `handle_deprecated_config()` function at lines 58-73 of [`lua/fff/conf.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/conf.lua) that automatically migrates old option names to new schemas. For example, the deprecated `width` option is migrated to `layout.width`. When the function detects deprecated keys, it emits a warning via `vim.notify` to alert you to update your configuration while still applying the correct values.