What is fff.nvim Main Entry Point? Complete Plugin Architecture Guide

The fff.nvim main entry point is plugin/fff.lua, which Neovim automatically executes on startup to register commands and defer initialization, while the public API resides in lua/fff.lua (re-exporting fff.main) where users access functions like find_files() and live_grep().

Understanding the entry point architecture of dmtrKovalenko/fff.nvim is essential for configuring and debugging this fast fuzzy finder. The plugin employs a two-stage initialization system that separates Neovim's startup sequence from the heavy lifting performed by its Rust-powered indexing backend.

The Two-Stage Entry Point Architecture

fff.nvim splits its initialization across conventional Neovim runtime paths to optimize startup performance. This design ensures that expensive operations—such as building the fuzzy search index—run only when absolutely necessary.

Stage 1: The Plugin Entry Point (plugin/fff.lua)

Neovim automatically sources all files in plugin/ directories during startup, making plugin/fff.lua the true fff.nvim main entry point. According to the source code, this file performs three critical tasks:

  • Registers public user commands including :FFFFind and :FFFScan
  • Defers heavy indexing work until after the UI is ready
  • Triggers require('fff.core').ensure_initialized() the first time a picker is invoked

This lazy initialization strategy prevents Neovim's startup time from being affected by the Rust backend compilation or file system scanning.

Stage 2: The Public API Module (lua/fff.lua)

When users call require('fff') in their configuration, they access lua/fff.lua. This file acts as a thin proxy that immediately re-exports the implementation:

-- lua/fff.lua
return require('fff.main')

The actual API implementation lives in lua/fff/main.lua, which contains the core functionality for setup(), find_files(), and live_grep().

How fff.nvim Initializes on Startup

The complete startup flow demonstrates the separation of concerns between the entry point and the core engine:


Neovim startup → loads plugin/fff.lua → sets up lazy init & commands
                → when a command or require('fff') is used,
                  lua/fff.lua → lua/fff/main.lua (core functionality)

By deferring require('fff.core').ensure_initialized() until the first picker invocation, the plugin maintains minimal impact on editor launch times while keeping the fuzzy finder immediately accessible via command mappings.

Practical Usage Examples

Installing with lazy.nvim

Even when using a plugin manager, the fff.nvim main entry point handles its own lazy loading internally:

-- Lazy-load with lazy.nvim (the plugin still self-initializes)
{
  'dmtrKovalenko/fff.nvim',
  lazy = false,   -- the plugin handles its own lazy loading
  opts = {        -- optional configuration passed to `require('fff').setup`
    lazy_sync = true,
    debug = { enabled = true, show_scores = true },
  },
}

Accessing the Public API

After the entry point has run, access the main functions through the public module:

-- Directly require the public module
local fff = require('fff')   -- this loads lua/fff.lua → lua/fff/main.lua

-- Open the file picker
fff.find_files()

-- Perform a live grep
fff.live_grep({ query = 'TODO' })

Triggering Initialization Manually

In rare cases where you need the core ready before UI interaction:

-- If you need the core to be ready before any picker interaction
require('fff.core').ensure_initialized()

Core Files in the Entry Point Chain

Understanding these source files clarifies the data flow from Neovim startup to fuzzy search execution:

  • plugin/fff.lua – The Neovim plugin entry point that registers commands and defers indexing
  • lua/fff.lua – Public module that users import with require('fff'), forwarding to fff.main
  • lua/fff/main.lua – Core API implementation containing setup(), find_files(), and live_grep()
  • lua/fff/core.lua – Initialization logic that ensures the Rust backend is ready
  • crates/fff-core/src/lib.rs – Rust backend performing the fast fuzzy search and indexing

Summary

  • fff.nvim main entry point is plugin/fff.lua, automatically sourced by Neovim on startup
  • The plugin defers heavy initialization until first use via require('fff.core').ensure_initialized()
  • Public API access flows through lua/fff.lualua/fff/main.lua when calling require('fff')
  • Commands like :FFFFind are registered immediately, but the Rust backend initializes lazily
  • Users configure the plugin through require('fff').setup() in their initialization files

Frequently Asked Questions

What file does Neovim load first when starting fff.nvim?

Neovim automatically loads plugin/fff.lua first because it resides in the plugin/ directory, which the runtime scans during startup. This file registers the user commands and sets up the lazy initialization hooks before any user configuration runs.

Why does fff.nvim use a two-stage entry point?

The two-stage architecture separates command registration (which must happen immediately) from resource-intensive indexing operations. By placing the heavy Rust backend initialization in fff.core and deferring it until first use, the plugin prevents Neovim's startup time from increasing while keeping the fuzzy finder instantly accessible via :FFFFind or :FFFScan.

How do I access the main fff.nvim functions in my configuration?

Import the public module with local fff = require('fff'), which returns the API defined in lua/fff/main.lua. This gives you access to fff.find_files(), fff.live_grep(), and fff.setup() for configuration. You do not need to manually require the entry point file; simply requiring 'fff' loads the full API after the initial plugin setup has occurred.

When is the Rust backend actually initialized?

The Rust backend initializes only when require('fff.core').ensure_initialized() is called, which happens automatically the first time you invoke a picker through :FFFFind, :FFFScan, or the Lua API functions. This lazy loading ensures that the computational cost of indexing your file system occurs after Neovim's UI is fully rendered and responsive.

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 →