Sort JSON Array in JavaScript
JavaScript's Array.prototype.sort() sorts JSON arrays in-place using a compare function. For arrays of objects — the most common case — you provide a comparator that extracts the property to sort by. Since ES2019, Array.sort() is guaranteed to be stable in all modern JavaScript engines.
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 Formatter