Sort JSON Array in JavaScript
Last updated:
JavaScript's Array.prototype.sort() sorts JSON arrays in-place and returns the same array — pass a comparator function to control the order. Without a comparator, sort() coerces every element to a string: [1, 10, 2].sort() produces [1, 10, 2] because "10" sorts before "2" lexicographically, not [1, 2, 10]. Since the ECMAScript 2019 spec, stable sort is guaranteed in V8, SpiderMonkey, and JavaScriptCore. This guide covers numeric comparators with a - b, sorting objects by a string property with localeCompare, multi-key sort, descending order, and the ES2023 Array.prototype.toSorted() method that returns a new array instead of mutating.
Paste your JSON array into Jsonic's formatter to validate it before sorting.
Open JSON FormatterSort array of strings
sort() without a comparator converts elements to strings and sorts lexicographically. This works correctly for simple string arrays.
const fruits = ["banana", "apple", "cherry", "date"]
fruits.sort()
// ["apple", "banana", "cherry", "date"]
// Non-destructive (returns new array)
const sorted = [...fruits].sort()Be careful: this approach fails for numbers. ["1","10","2"].sort() produces ["1","10","2"] because "10" sorts before "2" lexicographically. Always use a compare function for numeric arrays.
Sort by number (ascending and descending)
The compare function receives two elements a and b. Return a negative number to place a before b, zero for equal, or positive to place b before a. a - b is the idiomatic ascending numeric sort.
const scores = [42, 7, 100, 3, 55]
// Ascending
scores.sort((a, b) => a - b) // [3, 7, 42, 55, 100]
// Descending
scores.sort((a, b) => b - a) // [100, 55, 42, 7, 3]Sort array of objects by a string property
Use localeCompare when sorting objects by a text field. It handles accents and locale-specific ordering correctly. For simple ASCII, a ternary comparison also works.
const users = [
{ id: 1, name: "Charlie" },
{ id: 2, name: "Alice" },
{ id: 3, name: "Bob" },
]
// Sort by name alphabetically
users.sort((a, b) => a.name.localeCompare(b.name))
// [Alice, Bob, Charlie]
// Alternative for plain ASCII
users.sort((a, b) =>
a.name < b.name ? -1 : a.name > b.name ? 1 : 0
)Sort by numeric property
Subtract the numeric properties directly in the compare function. Flip the operands to switch between ascending and descending order.
const products = [
{ id: 1, name: "Widget", price: 29.99 },
{ id: 2, name: "Gadget", price: 9.99 },
{ id: 3, name: "Doohickey", price: 49.99 },
]
// Ascending by price
products.sort((a, b) => a.price - b.price)
// [Gadget $9.99, Widget $29.99, Doohickey $49.99]
// Descending by price
products.sort((a, b) => b.price - a.price)
// [Doohickey $49.99, Widget $29.99, Gadget $9.99]Sort by date
ISO 8601 date strings (YYYY-MM-DD) sort correctly with simple string comparison because the most-significant component comes first. For other date formats, parse to Date objects first.
const events = [
{ title: "Meeting", date: "2024-03-15" },
{ title: "Launch", date: "2024-01-01" },
{ title: "Review", date: "2024-06-10" },
]
// Sort chronologically (ISO strings compare correctly as strings)
events.sort((a, b) => a.date.localeCompare(b.date))
// [Launch 2024-01-01, Meeting 2024-03-15, Review 2024-06-10]
// Or convert to Date objects for non-ISO strings
events.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime())Sort by multiple fields
Chain comparisons inside the compare function to achieve a primary sort and a secondary tiebreaker. This technique is called a lexicographic tuple comparison.
// Sort by department first, then by salary descending
const employees = [
{ name: "Alice", dept: "Engineering", salary: 95000 },
{ name: "Bob", dept: "Marketing", salary: 70000 },
{ name: "Carol", dept: "Engineering", salary: 105000 },
{ name: "Dave", dept: "Marketing", salary: 80000 },
]
employees.sort((a, b) => {
// Primary: dept ascending
const deptCmp = a.dept.localeCompare(b.dept)
if (deptCmp !== 0) return deptCmp
// Secondary: salary descending
return b.salary - a.salary
})
// Result:
// Carol (Engineering, $105k)
// Alice (Engineering, $95k)
// Dave (Marketing, $80k)
// Bob (Marketing, $70k)Case-insensitive sort
By default, uppercase letters sort before lowercase in ASCII order, which produces surprising results for mixed-case arrays. Use localeCompare with the sensitivity: 'base' option to sort case-insensitively.
const tags = ["JSON", "api", "Base64", "yaml"]
// Bad: uppercase sorts before lowercase in default ASCII order
tags.sort() // ["Base64", "JSON", "api", "yaml"]
// Good: case-insensitive with localeCompare sensitivity option
tags.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }))
// ["api", "Base64", "JSON", "yaml"]Non-destructive sort (don't modify the original)
Array.prototype.sort() sorts in-place and returns the same array reference. To preserve the original, clone the array first with spread syntax, or use the ES2023 toSorted() method.
const original = [3, 1, 4, 1, 5, 9]
// ES2023: Array.prototype.toSorted()
const sorted = original.toSorted((a, b) => a - b)
// sorted → [1, 1, 3, 4, 5, 9]
// original → [3, 1, 4, 1, 5, 9] — unchanged
// Or spread + sort (works in all environments)
const sorted2 = [...original].sort((a, b) => a - b)
console.log(original) // [3, 1, 4, 1, 5, 9] — unchangedCompare function return values — quick reference
| Return value | Sort order | Typical pattern |
|---|---|---|
| Negative (e.g. -1) | a before b | a - b (ascending numbers) |
| 0 | Equal — original order preserved | a.localeCompare(b) returns 0 |
| Positive (e.g. 1) | b before a | b - a (descending numbers) |
Frequently asked questions
Why does array.sort() give wrong results for numbers?
Without a compare function, sort() converts every element to a string and sorts lexicographically. "10" comes before "2" lexicographically, so [1,10,2] sorts as [1,10,2] instead of [1,2,10]. Always pass (a, b) => a - b for numeric arrays.
Is JavaScript's Array.sort() stable?
Yes, in all modern engines (V8, SpiderMonkey, JavaScriptCore) and guaranteed by the ECMAScript 2019 spec. Elements that compare as equal preserve their original order.
How do I sort without modifying the original array?
Use the spread operator [...arr].sort() to clone first, or use the ES2023 Array.prototype.toSorted() method, which returns a new sorted array and leaves the original untouched.
How do I sort by a property in descending order?
Reverse the subtraction in the compare function: (a, b) => b.property - a.property for numbers, or (a, b) => b.name.localeCompare(a.name) for strings.
How do I sort an array of objects by multiple properties?
Chain comparisons in the compare function: compute the primary sort, return it if non-zero, otherwise compute and return the secondary sort. This is called a lexicographic tuple comparison.
What is localeCompare and when should I use it?
localeCompare compares strings according to locale conventions, handling accented characters, case sensitivity, and language-specific rules. Use it instead of < > operators whenever sorting text that users will read, especially for non-ASCII content.
Validate your JSON arrays
Paste any JSON array into Jsonic's formatter to validate and pretty-print it.
Open JSON FormatterRecommended reading
- Effective TypeScript (2nd Edition) — Dan Vanderkam83 concrete ways to level up your TypeScript — inference, narrowing, and type-safe API boundaries.
- JavaScript: The Definitive Guide (7th Edition) — David FlanaganThe complete reference for the language JSON came from — serialization, async, and the full standard library.
As an Amazon Associate, Jsonic earns from qualifying purchases.