Language Implementations

Sorting Algorithms in JavaScript

Implement sorting algorithms in JavaScript and learn how Array.prototype.sort() works, including the classic numeric-compare gotcha and V8's use of Tim Sort.

Aman Jaiman
10 min read
On this page +
  1. In plain English
  2. The Array.sort gotcha
  3. What engines use
  4. Quick Sort in JavaScript
  5. What algorithm does Array.prototype.sort use?
  6. The numeric gotcha you must know
  7. Frequently asked questions

Sorting in JavaScript has a famous gotcha that trips up beginners, plus a modern engine implementation worth understanding. This guide covers Array.prototype.sort(), the compare-function trap, and clean implementations of the classic algorithms.

The Array.sort gotcha #

By default, Array.prototype.sort() converts elements to strings and sorts lexicographically — so [10, 2, 1].sort() returns [1, 10, 2]! Always pass a compare function for numbers: arr.sort((a, b) => a - b). This is the single most common JavaScript sorting bug.

What engines use #

Since 2018, V8 (Chrome, Node.js) implements Array.prototype.sort() with Tim Sort. The ECMAScript spec has required sort to be stable since ES2019, so behavior on equal elements is now consistent across modern browsers. See JavaScript's Array.sort algorithm for more.

Quick Sort in JavaScript #

function quickSort(arr) {
  if (arr.length <= 1) return arr;
  const [pivot, ...rest] = arr;
  const left = rest.filter((x) => x < pivot);
  const right = rest.filter((x) => x >= pivot);
  return [...quickSort(left), pivot, ...quickSort(right)];
}

What algorithm does Array.prototype.sort use? #

The specification does not name an algorithm, so this is an engine-by-engine question — but since 2018 the answer has converged.

V8 (Chrome, Node.js, Edge) uses Tim Sort. V8 switched in version 7.0, shipping with Chrome 70. Before that it used Insertion Sort for arrays of 10 or fewer elements and Quick Sort above that — which was unstable, so equal elements could be reordered unpredictably depending on array length. SpiderMonkey (Firefox) uses Merge Sort, and JavaScriptCore (Safari) also uses a stable merge-based sort.

Crucially, this is no longer left to chance. ES2019 made stability a specification requirement, so every compliant modern engine must preserve the relative order of equal elements. Code that relied on the old unstable behaviour was already broken; code that assumes stability is now safe.

The numeric gotcha you must know #

This is the single most common JavaScript sorting bug, and it is not a bug in the engine:

[1, 10, 9, 2].sort();
// → [1, 10, 2, 9]   ...not what you wanted

With no comparator, sort() converts every element to a string and compares those strings by UTF-16 code unit. As text, "10" really does come before "9", exactly as "apple" comes before "banana". The array is correctly sorted — just not numerically.

The fix is to always pass a comparator when sorting numbers:

[1, 10, 9, 2].sort((a, b) => a - b);
// → [1, 2, 9, 10]

Two related traps. sort() mutates the array in place and returns the same reference, so it does not give you a sorted copy — use toSorted() in modern runtimes, or [...arr].sort(), if you need the original preserved. And undefined values are always moved to the end regardless of your comparator, without ever being passed to it.

Found this useful?

Share it with someone who is learning this too.

Questions

Frequently asked questions

What algorithm does JavaScript Array.sort() use? +
V8 (Chrome, Node.js) uses Tim Sort since 2018. Firefox's SpiderMonkey uses a Merge Sort variant. The spec requires stability since ES2019 but does not mandate a specific algorithm.
Why does JavaScript sort numbers incorrectly? +
Because the default sort converts values to strings and compares them lexicographically. Pass a compare function like (a, b) => a - b to sort numbers correctly.
Is JavaScript's Array.sort stable? +
Yes, in any modern engine. ES2019 made stability a specification requirement, so equal elements must keep their relative order. Historically it was not guaranteed — V8 used an unstable Quick Sort for arrays longer than 10 elements before version 7.0 (Chrome 70) — so very old environments could reorder equal items. You can rely on stability today.
What algorithm does V8 use for sorting? +
Tim Sort, since V8 7.0 (Chrome 70, 2018). It is an adaptive hybrid of Merge Sort and Insertion Sort that is stable and exploits already-sorted runs in the data. Before that, V8 used Insertion Sort for arrays of 10 or fewer elements and an unstable Quick Sort for anything larger.
Why does sort() put 10 before 9? +
Because with no comparator, sort() converts elements to strings and compares them as text. The string "10" sorts before "9" because the character "1" precedes "9". Pass a numeric comparator — .sort((a, b) => a - b) — whenever you are sorting numbers.

See it in motion

Watch this algorithm and nine others run step by step, with live pseudocode and comparison counters.

Launch the visualiser
Aman Jaiman
Written by
Aman Jaiman

Software engineer at a stealth-stage startup, and previously a front-end engineer for around a year and a half.

Keep reading

Related guides

Link copied