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
--nthimproves search performance by limiting tokenization to specific fields, reducing the search index size, and enabling pattern caching insrc/terminal.go.--with-nthadds display overhead through per-line tokenization and transformation insrc/core.gowithout 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, andsrc/pattern.goconfirm that--nthreduces computational complexity while--with-nthshifts 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →