Performance Implications of fzf `--nth` and `--with-nth` Options: A Deep Dive

The --nth option improves search performance by limiting tokenization to specific fields, while --with-nth adds per-line display overhead without affecting matching speed.

Understanding the performance implications of the --nth and --with-nth options in junegunn/fzf helps you optimize large-scale fuzzy searches. These flags control which fields participate in matching versus which fields appear in the interface, with significantly different computational costs.

How --nth Affects Performance

The --nth flag restricts fuzzy matching, sorting, and highlighting to specific field ranges. According to the source code in src/options.go (lines 60-67), this selection is stored in opts.Nth as a slice of Range structs.

Reduced Search Space and Tokenization

When you specify --nth, the matcher in src/core.go (line 236) receives the restricted range and builds patterns using only those tokens. The BuildPattern function passes the nth slice directly to the matcher, which then calls Transform (implemented in src/tokenizer.go, lines 263-335) to select only the specified fields.

This reduces the number of tokens per item, creates a smaller search index, and minimizes character comparisons during the fuzzy matching algorithm.

Pattern Caching Benefits

The terminal implementation in src/terminal.go (lines 6327-6329) caches compiled patterns keyed by the nth configuration. When the nth value remains constant across searches, fzf avoids rebuilding the search state, improving cache locality and reducing CPU overhead.

Parsing Overhead

Parsing --nth occurs once during option initialization via splitNth in src/options.go. This is an O(m) operation where m equals the number of comma-separated ranges, resulting in negligible startup cost.

How --with-nth Affects Performance

The --with-nth option transforms line presentation before display and ANSI-color handling. Stored in opts.WithNth as a function type (defined in src/options.go, lines 76-83), this flag affects rendering, not matching.

Per-Line Tokenization Cost

When --with-nth is active, the chunk-list writer in src/core.go (lines 24-46) tokenizes every input line regardless of whether the matcher needs those fields. The Tokenize function processes each line during the reading loop, adding overhead proportional to input size.

Transformation Overhead

After tokenization, the system calls nthTransformer (via Transform(tokens, nth)) and then JoinTokens to reconstruct the display string. This adds O(k) cost per line, where k represents the number of tokens touched by the transformation.

No Impact on Matching

Critically, the transformed text is not fed to the matcher. The matcher continues using the original line or the --nth-selected fields if both flags are set. Consequently, --with-nth provides no search acceleration and only adds CPU work for display rendering.

Comparing --nth vs --with-nth Performance

Performance Aspect --nth --with-nth
Search Speed Improves by reducing token set No effect
Tokenization Reduces matcher workload Adds per-line overhead
Memory Usage Lower (smaller indexes) Higher (stores transformed strings)
CPU Impact Caching benefits Continuous transformation cost
Use Case Narrow search domain Clean presentation

When to Use Each Flag for Optimal Performance

Situation Recommended Flag Implementation Details
CSV-like data where only the 2nd column matters for matching --nth=2 or -n 2 opts.Nth receives []Range{{begin:2,end:2}}; matcher builds patterns on single token only
Display only columns 2-4 while searching the whole line --with-nth={2..4} Transform in src/tokenizer.go selects fields after matching; full line still indexed
Reduced search space and trimmed view -n 2 --with-nth={2} Search runs on column 2 only via BuildPattern with nth parameter; UI shows only column 2 via nthTransformer

Code Examples and Implementation Details

The following examples demonstrate the performance characteristics in practice:


# Search only the 3rd field (fastest matching)

# Corresponds to opts.Nth = []Range{{begin:3,end:3}}

fzf -d ':' -n 3 < data.txt

# Show only fields 2-4 but search the whole line (no speed gain)

# Triggers Transform() in src/tokenizer.go for every line

fzf -d ',' --with-nth={2..4} < data.txt

# Fast search AND trimmed view (optimal performance)

# BuildPattern receives nth for matching; nthTransformer runs for display

fzf -d '\t' -n 2 --with-nth={2}

In the first example, src/core.go line 236 passes the restricted range to BuildPattern, which constructs the matcher with limited tokens. In the second example, src/core.go lines 24-46 process the transformation after reading but before storage, adding overhead without benefiting the search algorithm.

Summary

  • --nth improves search performance by limiting tokenization to specific fields, reducing the search index size, and enabling pattern caching in src/terminal.go.
  • --with-nth adds display overhead through per-line tokenization and transformation in src/core.go without affecting the matcher speed.
  • Combining both flags provides the fastest search experience while maintaining a clean interface, as the matcher works on a minimal dataset while the UI renders transformed output.
  • Implementation details in src/options.go, src/tokenizer.go, and src/pattern.go confirm that --nth reduces computational complexity while --with-nth shifts work to the rendering pipeline.

Frequently Asked Questions

Does --nth make fzf searches faster?

Yes. The --nth option restricts fuzzy matching to specific fields, which reduces the number of tokens the matcher must process. According to the implementation in src/core.go and src/pattern.go, this creates a smaller search index and fewer character comparisons. Additionally, src/terminal.go caches patterns based on the nth configuration, avoiding redundant computation when the field selection remains constant.

Does --with-nth slow down fzf?

Yes, but only slightly and only for display rendering. The --with-nth option triggers additional per-line processing in src/core.go, where each line undergoes tokenization and transformation via Transform in src/tokenizer.go before storage. This adds CPU overhead proportional to the number of tokens transformed. However, since the matcher still operates on the original line (or --nth-selected fields), the fuzzy search speed itself remains unaffected.

Can I use --nth and --with-nth together?

Yes, and this combination often provides the best performance. When used together, --nth limits the matcher to specific fields (reducing search complexity), while --with-nth ensures the display shows exactly those fields (or a different subset). For example, fzf -d '\t' -n 2 --with-nth={2} searches only the second tab-delimited column and displays only that column, minimizing both computational and cognitive overhead.

Which flag reduces memory usage?

The --nth flag reduces memory usage by limiting the data structures used during matching. By restricting tokenization to specific fields, fzf creates smaller search indexes and caches fewer pattern states in memory. In contrast, --with-nth does not reduce memory usage; it may slightly increase it because the system stores both the original line (for matching) and the transformed representation (for display) during the processing pipeline in src/core.go.

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 →