How Lodash sortBy Handles Stable Sorting

Lodash’s _.sortBy function creates a new array of sorted elements based on specified iteratees, guaranteeing a stable sort across all JavaScript environments. A sorting algorithm is considered stable when elements with identical sorting keys retain their original relative order in the output. This article examines the internal mechanisms Lodash uses to enforce stable sorting, how it compares equal values, and why this behavior ensures consistency regardless of engine implementation.

The Principle of Stable Sorting in Lodash

When sorting an array of objects, items often have duplicate sort criteria. In an unstable sort, the relative positioning of these equal items is not guaranteed and can change unpredictably.

Lodash ensures stability by tracking the original position of every element before performing any comparisons. Even if multiple objects produce identical values when evaluated against the sorting iteratees, _.sortBy relies on the original insertion order as an automatic tiebreaker.

The Underlying Mechanism: Index Tracking

To maintain stability across various runtimes, Lodash internally normalizes the collection into intermediate data structures before sorting. The process works as follows:

  1. Mapping Criteria and Indexes: Lodash iterates through the input collection and transforms each item into an internal object. This internal representation stores the computed sort criteria values alongside the item's original array index.
  2. Multi-Tier Comparison: During the sorting phase, Lodash performs an ascending comparison on the computed criteria. If the criteria for two items are identical, Lodash falls back to comparing their recorded original indexes.
  3. Restoring the Output: Because the original index is used as the final tiebreaker, an item that appeared earlier in the original array will always be placed before an item with the same key that appeared later. Finally, Lodash unwraps the sorted intermediate structures back into the final result array.
const users = [
  { id: 1, group: 'A' },
  { id: 2, group: 'B' },
  { id: 3, group: 'A' }
];

const sorted = _.sortBy(users, 'group');

// Result:
// [
//   { id: 1, group: 'A' },
//   { id: 3, group: 'A' },
//   { id: 2, group: 'B' }
// ]
// Notice that id: 1 still precedes id: 3 because their original order is preserved.

Cross-Browser Reliability

Historically, the ECMAScript specification did not require native Array.prototype.sort to be stable. Browsers implemented different algorithms; for example, older versions of Google's V8 engine used an unstable Quicksort for arrays containing more than ten elements.

Lodash implemented its own index-preservation mechanism to guarantee identical, deterministic behavior across all browsers and Node.js versions. While ECMAScript 2019 (ES10) eventually mandated that native JavaScript sorting must be stable (often via TimSort), Lodash's _.sortBy retains its explicit fallback logic, providing complete predictability across legacy and modern execution environments alike.