How to Use the fzf --tiebreak Option to Control Result Sorting

The --tiebreak option in fzf specifies secondary sorting criteria used to order results when multiple items receive identical fuzzy-match scores, accepting a comma-separated list of up to three values from length, chunk, pathname, begin, end, and index.

The junegunn/fzf command-line fuzzy finder ranks search results using a scoring algorithm that evaluates how closely each item matches the query pattern. When two or more candidates achieve the same fuzzy score, the --tiebreak option determines their relative order by applying additional comparison criteria. Understanding how this sorting mechanism works allows you to customize result ordering to match your specific workflow, whether you prefer shorter filenames, matches clustered together, or preserving input sequence.

What Is the fzf --tiebreak Option?

The --tiebreak option defines a priority list of secondary sorting criteria that fzf applies after computing the primary fuzzy-match score. By default, fzf uses length as the sole tiebreaker, meaning that when scores are equal, shorter entries appear before longer ones.

You can specify multiple criteria as a comma-separated list (maximum of three criteria besides the mandatory score), and fzf evaluates them in the order provided. For example, --tiebreak=chunk,length first compares the size of the matching chunk, then falls back to line length if the chunk sizes are identical.

Available Tiebreak Criteria

The junegunn/fzf source code defines six distinct criteria you can use with --tiebreak. Each criterion computes a specific metric that influences the final sort order:

length

length compares the trimmed length of the candidate line. Shorter lines receive higher priority (are sorted earlier). This is the default behavior when no --tiebreak option is specified.

chunk

chunk measures the size of the smallest contiguous "chunk" that contains all matched characters. Smaller chunks indicate that the match characters are clustered together rather than scattered across the string, which typically represents a more relevant match.

pathname

pathname calculates the distance from the last path separator to the start of the match. This criterion prioritizes matches that appear closer to the end of file paths (the filename itself), making it useful when searching through directory structures.

begin

begin measures the distance from the start of the line to the first matched character. Lower values (matches closer to the beginning) receive higher priority.

end

end uses the inverse of the distance from the end of the line to the last matched character. Matches closer to the end of the line receive higher priority.

index

index preserves the original input order. Because this criterion acts as a final fallback, it must be the last item in your --tiebreak list if included. It ensures deterministic ordering when all other metrics are equal.

How Tiebreak Sorting Works Internally

Understanding the internal implementation helps clarify why the --tiebreak option behaves the way it does. The sorting mechanism involves three main components in the junegunn/fzf codebase: option parsing, criteria propagation, and result scoring.

Parsing and Validation in options.go

When you provide --tiebreak on the command line, the parser in src/options.go invokes the parseTiebreak function (lines 1306–1362). This function:

  • Splits the comma-separated list into individual criteria
  • Validates that no duplicates exist
  • Ensures you specify at most three criteria (besides the mandatory score)
  • Verifies that index appears last if present, since it serves as the final fallback

The validated list is stored in opts.Criteria for later use.

Criteria Propagation in core.go

After parsing, src/core.go (line 79) copies the criteria list from the options structure to a package-level variable named sortCriteria. This makes the tiebreak configuration available to the scoring logic during the search execution.

Scoring and Point Allocation in result.go

The actual sorting comparison happens in src/result.go within the buildResult function (lines 52–108). Each candidate match is transformed into a Result structure containing four 16-bit unsigned integers called points.

The function iterates over sortCriteria and fills the points array in reverse order (result.points[3-idx] = val). This encoding strategy allows fzf to compare results as a single 64-bit big-endian unsigned integer, where earlier criteria occupy higher-order bits and therefore dominate the comparison.

The specific metrics computed include:

  • byScore: max_uint16 - score (higher original scores produce larger values)
  • byLength: Trimmed line length (shorter lines get larger values)
  • byChunk: Size of the smallest chunk containing all matches
  • byPathname: Distance from last path separator to match start
  • byBegin: Distance from line start to first match character
  • byEnd: Inverse distance from line end to last match character
  • byIndex: Original input index (final fallback)

Practical Examples

These command-line examples demonstrate how different --tiebreak configurations affect result ordering in real-world usage.

Prefer shorter filenames when scores are equal:

fzf --tiebreak=length

Prioritize matches where query characters appear close together, falling back to shorter lines:

fzf --tiebreak=chunk,length

Favor matches appearing in the filename portion of paths (useful for file searching):

fzf --tiebreak=pathname

Preserve the original file list order when all other metrics tie:

fzf --tiebreak=index

Combine up to three criteria, ensuring index remains last:

fzf --tiebreak=chunk,pathname,index

Summary

  • The fzf --tiebreak option defines secondary sorting criteria applied when candidates receive identical fuzzy-match scores.
  • The default value is length, causing shorter entries to appear first during ties.
  • Available criteria include length, chunk, pathname, begin, end, and index, which can be combined in comma-separated lists of up to three items.
  • The implementation encodes criteria into a 64-bit integer in src/result.go, allowing efficient comparison during the search process.
  • Criterion index must always appear last in the list and serves as the final fallback to preserve input order.

Frequently Asked Questions

What is the default tiebreak behavior in fzf?

By default, fzf uses --tiebreak=length. When two or more items achieve the same fuzzy-match score, the shorter line appears first in the results. This default prioritizes concise matches over longer strings containing the same pattern.

Can I use multiple tiebreak criteria at once?

Yes, you can specify up to three criteria as a comma-separated list. For example, --tiebreak=chunk,pathname,length first compares chunk size, then pathname proximity, then line length. The index criterion must always be last if included, as it acts as the final fallback.

Why does the index criterion have to be last?

The index criterion represents the original input order and serves as the ultimate tiebreaker when all other metrics are equal. The parser in src/options.go enforces this constraint because index provides deterministic ordering only when applied after all qualitative comparisons have failed to distinguish candidates.

How does chunk tiebreaking differ from length tiebreaking?

While length simply compares the total trimmed length of the candidate line, chunk measures the size of the smallest contiguous substring containing all matched characters. A smaller chunk indicates that the query characters appear clustered together rather than scattered across the line, which often signals a more relevant match even if the total line length is longer.

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 →