JavaScript Array Reduce Method: Complete Guide

reduce() turns an array into a single value by running an accumulator function on every element. Learn summing, grouping, flattening, and more.

6 min read

reduce() is the most powerful and flexible array method in JavaScript. It takes an array and reduces it to a single value -- a number, a string, an object, or even another array. Every other array method can be implemented with reduce().

reduce walks through elements accumulating a result

The accumulator starts at an initial value. For each element, the callback updates the accumulator. After the last element, the accumulator becomes the final result.

Syntax and the Accumulator Pattern

reduce() takes a callback and an optional starting value, then calls the callback once per element, passing along whatever it returned last time:

javascriptjavascript
array.reduce((accumulator, element) => {
  return newAccumulator;
}, initialValue);

There are four key pieces:

PieceDescription
accumulatorThe value carried forward from the previous iteration
elementThe current array element
Return valueBecomes the accumulator for the next iteration
initialValueThe starting value of the accumulator (optional, but recommended)

Here is the simplest example, summing numbers, which shows the pattern in its smallest useful form:

javascriptjavascript
const numbers = [1, 2, 3, 4];
 
const sum = numbers.reduce((acc, n) => acc + n, 0);
 
console.log(sum); // 10

Tracing through each call shows exactly how the accumulator grows on every step, from the initial value all the way to the final result:

texttext
Start:     acc = 0 (initial value)
Element 1: acc = 0 + 1 = 1
Element 2: acc = 1 + 2 = 3
Element 3: acc = 3 + 3 = 6
Element 4: acc = 6 + 4 = 10
Final:      10

Always Provide an Initial Value

Without an initial value, reduce() uses the first array element as the accumulator and starts from the second element. This works for simple sums but fails on empty arrays:

javascriptjavascript
const numbers = [1, 2, 3];
const sum = numbers.reduce((acc, n) => acc + n); // ok: acc starts at 1
console.log(sum); // 6
 
const empty = [];
const result = empty.reduce((acc, n) => acc + n); // TypeError!

Always provide an initial value. It makes the behavior predictable and avoids runtime errors.

Building an Object with reduce()

reduce() can build objects. A common use is counting occurrences:

javascriptjavascript
const fruits = ["apple", "banana", "apple", "orange", "banana", "apple"];
 
const counts = fruits.reduce((acc, fruit) => {
  acc[fruit] = (acc[fruit] || 0) + 1;
  return acc;
}, {});
 
console.log(counts); // { apple: 3, banana: 2, orange: 1 }

Notice that the callback must return the accumulator each time. Forgetting the return statement is the most common reduce() bug, and it silently breaks the whole chain of iterations:

javascriptjavascript
// Wrong: forgets to return the accumulator
const counts = fruits.reduce((acc, fruit) => {
  acc[fruit] = (acc[fruit] || 0) + 1;
}, {});
console.log(counts); // undefined (accumulator was lost)

Grouping Objects by a Property

reduce() is excellent for grouping an array of objects by a shared key. The accumulator starts as an empty object, and each element adds itself to the array under its matching key:

javascriptjavascript
const people = [
  { name: "Alice", role: "developer" },
  { name: "Bob", role: "designer" },
  { name: "Carol", role: "developer" },
  { name: "Dave", role: "designer" }
];

Each person gets pushed into the array under their role, creating that array the first time a new role is seen, so no role is ever left uninitialized:

javascriptjavascript
const grouped = people.reduce((acc, person) => {
  const key = person.role;
  if (!acc[key]) acc[key] = [];
  acc[key].push(person);
  return acc;
}, {});

The result is one array per role, each holding the full person objects that share that role, which is exactly the shape you would want for rendering grouped lists in a UI:

javascriptjavascript
console.log(grouped.developer.map(p => p.name)); // ["Alice", "Carol"]
console.log(grouped.designer.map(p => p.name));  // ["Bob", "Dave"]

Flattening an Array of Arrays

Before flat() existed, reduce() was the standard way to flatten a nested array, using concat() to merge each inner array into the accumulator:

javascriptjavascript
const nested = [[1, 2], [3, 4], [5, 6]];
 
const flat = nested.reduce((acc, arr) => acc.concat(arr), []);
 
console.log(flat); // [1, 2, 3, 4, 5, 6]

Today arr.flat() or arr.flatMap() is cleaner for this. For one-to-many mapping with flattening, see flatMap.

Finding Maximum and Minimum

reduce() can find the minimum or maximum element by custom logic, which is useful for objects where Math.min() and Math.max() do not directly apply:

javascriptjavascript
const products = [
  { name: "Laptop", price: 999 },
  { name: "Mouse", price: 29 },
  { name: "Monitor", price: 299 }
];
 
const cheapest = products.reduce((min, product) =>
  product.price < min.price ? product : min
);
 
console.log(cheapest); // { name: "Mouse", price: 29 }

This omits the initial value on purpose. Since the array is known to be non-empty, the first product safely becomes the starting min. If the array might be empty, provide an initial value to avoid a TypeError.

reduce() vs Other Methods

TaskWith reduce()Simpler Alternative
Transform elementsreduce((acc, n) => [...acc, n*2], [])map(n => n * 2)
Select elementsreduce((acc, n) => n>5 ? [...acc, n] : acc, [])filter(n => n > 5)
Check any/allreduce((acc, n) => acc && n>0, true)every(n => n > 0)
Sum valuesreduce((a, n) => a + n, 0)(reduce is best here)
Group by key(reduce is best here)(reduce is best here)

Use the simplest method that works. If map() or filter() can do the job, use them. Reach for reduce() when the result is a different shape from the input -- a single value, a grouped object, or a custom data structure.

Common Mistakes

Forgetting the initial value. Calling reduce() on an empty array with no initial value has nothing to use as a starting accumulator, so it throws instead of returning a default:

javascriptjavascript
const empty = [];
empty.reduce((acc, n) => acc + n); // TypeError
 
empty.reduce((acc, n) => acc + n, 0); // 0

Forgetting to return the accumulator. Mutating the accumulator without returning it loses the value on the very next call, since reduce() always uses whatever the callback returned:

javascriptjavascript
const result = [1, 2, 3].reduce((acc, n) => {
  acc.push(n * 2); // mutates but doesn't return
}, []);
console.log(result); // undefined

Adding the missing return fixes it, since the accumulator now carries forward correctly on every call instead of silently turning into undefined:

javascriptjavascript
const resultFixed = [1, 2, 3].reduce((acc, n) => {
  acc.push(n * 2);
  return acc;
}, []);
console.log(resultFixed); // [2, 4, 6]

When the callback uses curly braces {}, you need an explicit return. Arrow functions with a single expression (() => expression) return implicitly.

Now that you understand reduce(), learn how to select specific elements with filter for creating subsets of your data.

Rune AI

Rune AI

Key Insights

  • reduce() processes every element and accumulates a single result value.
  • The accumulator carries the result from one iteration to the next.
  • Always provide an initial value to avoid errors on empty arrays.
  • reduce() can sum numbers, group objects, flatten arrays, and build any data structure.
  • Keep reduce() callbacks readable. If they get complex, use named functions.
RunePowered by Rune AI

Frequently Asked Questions

What happens if I call reduce() on an empty array without an initial value?

It throws a TypeError. If the array is empty and no initial value is provided, reduce() has nothing to return. Always provide an initial value when the array might be empty.

When should I use reduce() instead of a for loop?

Use reduce() when you need to derive a single value (sum, object, grouped map) from an array and want a functional, chainable approach. Use a for loop when you need more complex control flow, early exits, or side effects inside the iteration.

Is reduce() always the right choice for summing numbers?

For simple sums, reduce() is fine. But for very large arrays or performance-critical code, a for loop can be faster. For most everyday code, the readability of reduce() outweighs the minor performance difference.

Conclusion

reduce() is the most powerful array method in JavaScript. It can replace map(), filter(), and nearly any other array transformation. But with great power comes a responsibility to keep it readable. Use reduce() when the transformation is naturally an accumulation -- summing, grouping, flattening, or building up a result. When the logic gets complex, break it into named functions or use a simpler method.