# Performance Benefits of fff.nvim's Rust Backend: SIMD-Accelerated Fuzzy Finding in Neovim

> Discover how fff.nvim's Rust backend delivers SIMD-accelerated fuzzy finding in Neovim. Experience orders-of-magnitude faster file searching with multi-threading and efficient data structures.

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

---

**fff.nvim achieves orders-of-magnitude faster file searching than pure-Lua implementations by offloading CPU-intensive fuzzy matching to a Rust backend that leverages SIMD instructions, multi-threading across all logical CPUs, and cache-friendly data structures.**

fff.nvim is a Neovim file finder plugin that splits its architecture between a minimal Lua UI layer and a high-performance Rust backend. This design eliminates the overhead of interpreted Lua for filesystem scanning and fuzzy string matching, delivering sub-second search results even in repositories with 100,000+ files.

## Architecture Overview: Thin Lua, Fast Rust

The plugin employs a deliberate architectural split that keeps the Lua side lightweight while pushing all heavy computation to compiled machine code.

- **Lua UI Layer** (`lua/fff/*.lua`): Handles the picker interface, parses user input, and forwards calls to the Rust side. This minimal wrapper approach avoids the algorithmic overhead of pure-Lua implementations.

- **Rust Backend** (`crates/fff-core`, `crates/fff-c`): Performs filesystem scanning, builds file-item caches, and executes fuzzy-search algorithms. The core data structures—`FileItem`, `Score`, and `FilePicker`—store pre-computed **frecency** (file open frequency) and **git status**, enabling rapid filtering without additional I/O operations.

- **FFI Glue** ([`crates/fff-c/src/lib.rs`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/crates/fff-c/src/lib.rs)): Exposes Rust functions as C-compatible symbols (`fff_*`) that Lua can call directly via `package.loadlib`. This creates a stable ABI where Lua receives plain pointers and frees them using dedicated `fff_free_*` functions.

## SIMD-Accelerated Fuzzy Matching

The Rust backend utilizes the `neo_frizbee` crate to evaluate millions of candidates in parallel using CPU vector registers.

In [`crates/fff-core/src/score.rs`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/crates/fff-core/src/score.rs), the `match_and_score_files` function constructs a `ScoringContext` and invokes `neo_frizbee::match_list_parallel`. This SIMD-based approach provides approximately **5× speed-up on x86_64** compared to scalar implementations by processing multiple characters simultaneously within CPU registers.

```rust
// crates/fff-core/src/score.rs
let options = neo_frizbee::Config {
    max_typos: Some(context.max_typos),
    sort: false,
    scoring: Scoring {
        capitalization_bonus: if has_uppercase { 8 } else { 0 },
        matching_case_bonus: if has_uppercase { 4 } else { 0 },
        ..Default::default()
    },
};
let path_matches = match_fuzzy_parts(
    fuzzy_parts, 
    &working_files, 
    &options, 
    context.max_threads
);

```

The algorithm also detects path separators in queries and falls back to specialized filename matching to maintain tight inner loops.

## Multi-Threaded Execution

By default, fff.nvim utilizes all available logical CPUs through `std::thread::available_parallelism`.

Both the fuzzy-matching stage and filename-fallback stages in [`score.rs`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/score.rs) use `neo_frizbee::match_list_parallel`, which distributes work across the configured thread count. For small result sets (under 10,000 matches), the system automatically falls back to single-threaded execution to minimize synchronization overhead.

```rust
// crates/fff-core/src/score.rs
let matches = neo_frizbee::match_list_parallel(
    fuzzy_parts[0],
    &fallback_filenames,
    &options,
    if path_matches.len() > 10_000 { context.max_threads } else { 1 },
);

```

This multi-core scaling reduces search latency in large projects from seconds to sub-second response times.

## Intelligent Caching and Scoring

The backend employs **cache-friendly data structures** that pre-compute expensive metadata during the initial filesystem scan.

- **Frecency tracking**: Files are scored based on how recently and frequently they were opened
- **Git status boost**: Dirty files receive a **15% scoring bonus**, prioritizing active work
- **Pre-computed path components**: Eliminating string parsing during the search hot path

These optimizations occur in [`crates/fff-core/src/file_picker.rs`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/crates/fff-core/src/file_picker.rs), where the `FilePicker` struct maintains the working set in memory layouts optimized for CPU cache lines.

## Zero-Copy FFI Integration

The Rust library compiles to a shared object (`libfff_nvim.so`, `.dll`, or `.dylib`) loaded directly via `package.loadlib` in [`lua/fff/rust/init.lua`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/lua/fff/rust/init.lua). This approach eliminates Lua `require`-time `cpath` pollution and ensures the exact binary is used without intermediate copying.

```lua
-- lua/fff/rust/init.lua
local function try_load_library()
  for _, path_pattern in ipairs(paths) do
    local actual_path = resolve_path(path_pattern:gsub('%?', 'fff_nvim'))
    local stat = vim.uv.fs_stat(actual_path)
    if stat and stat.type == 'file' then
      local loader, err = package.loadlib(actual_path, 'luaopen_fff_nvim')
      -- ...
    end
  end
end

```

The FFI boundary in [`crates/fff-c/src/lib.rs`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/crates/fff-c/src/lib.rs) returns opaque pointers to `FffSearchResult` and `FffGrepResult` structures, which Lua wrappers expose as tables without data duplication until conversion is necessary.

## Practical Implementation Examples

### Opening the Fuzzy File Picker

```lua
local fff = require('fff')
local ui = require('fff.picker_ui')

ui.open({
  prompt = 'Find file: ',
  initial_query = '',
  on_select = function(item)
    -- item.path populated by Rust search results
    vim.cmd('edit ' .. item.path)
  end,
})

```

### Performing Live Grep Searches

```lua
local fff = require('fff')
local result = fff.fuzzy.live_grep('fn main', 0, 0, false, 0, 0, 0, false, 0, 10)

for i = 0, result.count - 1 do
  local match = result:get_match(i)  -- calls fff_grep_result_get_match
  print(string.format('%s:%d %s', match.file_path, match.line, match.text))
end

```

### Forcing a Filesystem Rescan

```lua
local fff_rust = require('fff.rust')
fff_rust.scan_files()  -- Re-index after mass file changes

```

## Summary

- **fff.nvim** offloads all CPU-bound work to a Rust backend while keeping the UI in Lua, minimizing interpreter overhead.
- **SIMD acceleration** via `neo_frizbee` provides ~5× speedup on modern x86_64 processors.
- **Multi-threading** automatically scales to all logical CPUs, handling 100,000+ file repositories in sub-second times.
- **Zero-copy FFI** through `package.loadlib` eliminates memory duplication between Lua and Rust.
- **Cache-friendly structures** with pre-computed frecency and git status avoid post-filter passes and I/O bottlenecks.

## Frequently Asked Questions

### How does fff.nvim's Rust backend improve search speed compared to Telescope or fzf-lua?

Pure-Lua file finders must execute fuzzy matching algorithms within the Lua interpreter, which lacks SIMD instructions and true multi-threading. According to the fff.nvim source code, the Rust backend in [`crates/fff-core/src/score.rs`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/crates/fff-core/src/score.rs) executes fuzzy matching using vectorized CPU instructions across multiple threads, resulting in orders-of-magnitude faster performance on large codebases.

### What is the neo_frizbee crate and why does it matter for performance?

The `neo_frizbee` crate is the underlying Rust library used in [`crates/fff-core/src/score.rs`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/crates/fff-core/src/score.rs) that provides `match_list_parallel`. It implements SIMD-accelerated fuzzy string matching algorithms that process multiple bytes simultaneously using CPU vector registers, delivering the approximately 5× speedup over scalar implementations observed in benchmarks.

### How does the multi-threading in fff.nvim work with large codebases?

The Rust backend detects the number of logical CPUs via `std::thread::available_parallelism` and passes this as `max_threads` to `neo_frizbee::match_list_parallel`. As implemented in [`score.rs`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/score.rs), the system automatically uses parallel processing when candidate lists exceed 10,000 items, while smaller sets use single-threaded execution to avoid synchronization overhead.

### Is there a performance penalty for the FFI communication between Lua and Rust?

The FFI design in [`crates/fff-c/src/lib.rs`](https://github.com/dmtrKovalenko/fff.nvim/blob/main/crates/fff-c/src/lib.rs) minimizes overhead by returning opaque pointers (`FffResult`) rather than copying data structures across the boundary. Lua calls dedicated `fff_free_*` functions to release memory, ensuring zero-copy operations where the Lua side only handles thin wrappers around Rust-allocated data.